C ++中十六进制字符串的整数


127

如何在C ++中将整数转换为十六进制字符串?

我可以找到一些方法来做到这一点,但它们似乎大多针对C。似乎没有C ++的本机方法。但是,这是一个非常简单的问题。我有一个int想要转换为十六进制字符串以便以后打印的字符串。

Answers:


225

使用<iomanip>std::hex。如果您要打印,只需将其发送到std::cout,否则请使用std::stringstream

std::stringstream stream;
stream << std::hex << your_int;
std::string result( stream.str() );

如果需要,您可以在第一个选项之前<<添加<< "0x"任何内容。

其他有趣的操作是std::oct(八进制)和std::dec(返回十进制)。

您可能会遇到的一个问题是,它会产生表示它所需的确切位数。您可以使用setfillsetw来解决此问题:

stream << std::setfill ('0') << std::setw(sizeof(your_type)*2) 
       << std::hex << your_int;

所以最后,我建议使用这样的功能:

template< typename T >
std::string int_to_hex( T i )
{
  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;
  return stream.str();
}

7
@MSalters-恰恰相反。测试您对int类型的建议;)
Kornel Kisielewicz

2
@LexFridman,根据需要精确地发出十六进制数字。如果类型是uint8_t,为什么还要输出8位数字?
Kornel Kisielewicz 2012

15
WARNIG:这对于单个字节将不起作用,因为char始终被威胁为char
ov7a,2016年

5
您还需要#include <sstream>
David Gausmann,

2
如果我格式化多个整数,看来std::setw需要输出到流为每INT,而std::hexstd::setfillstd::uppercase,......只需要发送一次输出流。这似乎不一致吗?
wcochran

39

为了使它更轻快,我建议使用直接填充字符串。

template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
    static const char* digits = "0123456789ABCDEF";
    std::string rc(hex_len,'0');
    for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
        rc[i] = digits[(w>>j) & 0x0f];
    return rc;
}

这适用于任何类型吗?我的意思是还double,float,uint8_t吗?
SR

@SR它适用于整数类型,不适用于doublefloat(且不适用于指针)
Wolf

... C和C ++非常实用(但有效)的混合,我不确定速度...就我的口味而言,它有点密集。

谢谢您的精彩回答。引入流库“只是”这样做似乎很浪费。
DeveloperChris

1
打印0000FFFF0xFFFF。我更喜欢有0xFFFF输出。
DrumM

24

使用std::stringstream转换成整数的字符串和其特殊的操纵器设置的基础。例如这样的例子:

std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();

14

只需将其打印为十六进制数字即可:

int i = /* ... */;
std::cout << std::hex << i;

7
我会使用std::cout<<std::hex<<i<<std::dec;,否则以后流出的所有整数都将为十六进制。您无需对其他使用的答案进行处理,stringstream因为流在使用后将被丢弃,但可以cout永久存在。
Mark Lakata

8

您可以尝试以下方法。运作中...

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

template <class T>
string to_string(T t, ios_base & (*f)(ios_base&))
{
  ostringstream oss;
  oss << f << t;
  return oss.str();
}

int main ()
{
  cout<<to_string<long>(123456, hex)<<endl;
  system("PAUSE");
  return 0;
}

1
一个很好的答案,但要注意to_string的是命名空间的一部分,std在C ++ 11
亚历克斯

@Alex是的,毕竟是2014年……天哪,我们必须尽快开始处理C ++ 14。
Alex

7

这个问题很老,但是我很惊讶为什么没有人提到boost::format

cout << (boost::format("%x") % 1234).str();  // output is: 4d2

4
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30

4

感谢林肯下面的评论,我更改了这个答案。

以下答案在编译时正确处理8位整数。但是,它需要C ++ 17。如果没有C ++ 17,则必须做其他事情(例如,提供此函数的重载,一个用于uint8_t,一个用于int8_t,或者使用“ if constexpr”之外的其他功能,也许是enable_if)。

template< typename T >
std::string int_to_hex( T i )
{
    // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
    static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

    std::stringstream stream;
    stream << "0x" << std::setfill ('0') << std::setw(sizeof(T)*2) << std::hex;

    // If T is an 8-bit integer type (e.g. uint8_t or int8_t) it will be 
    // treated as an ASCII code, giving the wrong result. So we use C++17's
    // "if constexpr" to have the compiler decides at compile-time if it's 
    // converting an 8-bit int or not.
    if constexpr (std::is_same_v<std::uint8_t, T>)
    {        
        // Unsigned 8-bit unsigned int type. Cast to int (thanks Lincoln) to 
        // avoid ASCII code interpretation of the int. The number of hex digits 
        // in the  returned string will still be two, which is correct for 8 bits, 
        // because of the 'sizeof(T)' above.
        stream << static_cast<int>(i);
    }        
    else if (std::is_same_v<std::int8_t, T>)
    {
        // For 8-bit signed int, same as above, except we must first cast to unsigned 
        // int, because values above 127d (0x7f) in the int will cause further issues.
        // if we cast directly to int.
        stream << static_cast<int>(static_cast<uint8_t>(i));
    }
    else
    {
        // No cast needed for ints wider than 8 bits.
        stream << i;
    }

    return stream.str();
}

原始答案无法正确处理8位整数,就像我认为的那样:

Kornel Kisielewicz的回答很好。但是,稍微增加一下就可以帮助您捕获使用模板参数调用此函数的情况,这些参数没有意义(例如,float)或会导致混乱的编译器错误(例如,用户定义的类型)。

template< typename T >
std::string int_to_hex( T i )
{
  // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
  static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;

         // Optional: replace above line with this to handle 8-bit integers.
         // << std::hex << std::to_string(i);

  return stream.str();
}

我已经对其进行了编辑,以添加对std :: to_string的调用,因为将8位整数类型(例如,std::uint8_t传递的值)std::stringstream视为char,但这不会为您提供所需的结果。将这样的整数传递给std::to_string正确处理它们,并且在使用其他较大的整数类型时也不会造成伤害。当然,在这种情况下,由于不必要进行std :: to_string调用,因此可能会对性能造成轻微影响。

注意:我只会在评论中将其添加到原始答案中,但是我没有代表要评论。


在我的测试std :: to_string(i)中,不会将std :: uint8_t整数打印为十六进制。我认为对于uint8_t和int8_t类型,这可能必须具有单独的条件,因为它们需要转换为较大的整数。
林肯

1
@林肯你是对的。我不知道当时(几个月前)当时在做什么,这使我无法使用to_string处理8位整数。我什至回到了我当时使用的编译器版本,只是为了仔细检查,但是to_string并没有像我所说的那样工作。那谁知道呢 无论如何,感谢您抓住了这个-我已经编辑了应该可以正常工作的答案。
失去心态

1
这仍然会意外地起作用char(这uint8_tint8_t大多数实现(在unsigned char和中分别是和signed char)都不同)。
罗斯兰

@ruslan是的,布尔型和宽字符型也都匹配std :: is_integral,并且不会使断言失败。但由于按标准,char是有保证的唯一类型,而宽char类型也是如此,因此您可以根据需要处理所有类型(例外是un / signed char,它与宽度为a的un / signed整数类型匹配字节位于当前计算机上-通常为int8-因此,如果您也要匹配相同宽度的int,则无法进行过滤。您可以通过向static_assert中添加更多术语来拒绝char,wide chars,bools ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>等:
Loss Mentality

2

对于那些发现很多/大多数ios::fmtflags不兼容的人(std::stringstream例如Kornel早在那时发布的模板想法),以下方法有效并且相对干净:

#include <iomanip>
#include <sstream>


template< typename T >
std::string hexify(T i)
{
    std::stringbuf buf;
    std::ostream os(&buf);


    os << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2)
       << std::hex << i;

    return buf.str().c_str();
}


int someNumber = 314159265;
std::string hexified = hexify< int >(someNumber);

9
您不应该只返回buf.str()吗?
ruipacheco

2

我做:

int hex = 10;      
std::string hexstring = stringFormat("%X", hex);  

看看iFreilicht的SO答案以及这里的GIST所需的模板头文件!


2

只需看一下我的解决方案,[1]我就从我的项目中逐字复制,所以其中包含了德语文档。我的目标是在实际需求中结合灵活性和安全性:[2]

  • 0x添加前缀:呼叫者可以决定
  • 自动扣除宽度:减少打字
  • 显式宽度控制:扩大格式,(无损)缩小以节省空间
  • 能够应付 long long
  • 限于整数类型:通过静默转换避免意外
  • 易于理解
  • 无硬编码限制
#include <string>
#include <sstream>
#include <iomanip>

/// Vertextet einen Ganzzahlwert val im Hexadezimalformat.
/// Auf die Minimal-Breite width wird mit führenden Nullen aufgefüllt;
/// falls nicht angegeben, wird diese Breite aus dem Typ des Arguments
/// abgeleitet. Funktion geeignet von char bis long long.
/// Zeiger, Fließkommazahlen u.ä. werden nicht unterstützt, ihre
/// Übergabe führt zu einem (beabsichtigten!) Compilerfehler.
/// Grundlagen aus: http://stackoverflow.com/a/5100745/2932052
template <typename T>
inline std::string int_to_hex(T val, size_t width=sizeof(T)*2)
{
    std::stringstream ss;
    ss << std::setfill('0') << std::setw(width) << std::hex << (val|0);
    return ss.str();
}

[1]基于Kornel Kisielewicz 的回答
[2]翻译成CppTest的语言,它的读法是:

TEST_ASSERT(int_to_hex(char(0x12)) == "12");
TEST_ASSERT(int_to_hex(short(0x1234)) == "1234");
TEST_ASSERT(int_to_hex(long(0x12345678)) == "12345678");
TEST_ASSERT(int_to_hex((long long)(0x123456789abcdef0)) == "123456789abcdef0");
TEST_ASSERT(int_to_hex(0x123, 1) == "123");
TEST_ASSERT(int_to_hex(0x123, 8) == "00000123");
// with deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012"); 

1
可以通过例如TEST_ASSERT(int_to_hex(short(0x12)) == "0012");
轨道竞赛中的“ Lightness Races”来

2

代码供您参考:

#include <iomanip>
#include <sstream>
...
string intToHexString(int intValue) {

    string hexStr;

    /// integer value to hex-string
    std::stringstream sstream;
    sstream << "0x"
            << std::setfill ('0') << std::setw(2)
    << std::hex << (int)intValue;

    hexStr= sstream.str();
    sstream.clear();    //clears out the stream-string

    return hexStr;
}

4
这实际上并没有添加到现有答案中,并且明确地clearsstream其毫无意义(无论如何,当函数在下一行返回时,它将被销毁)。您可以hexStr完全避免使用named ,return sstream.str();而无需clearing并获得相同的效果,将四行代码减少为一行。
ShadowRanger

1
当论坛的目的是了解事物和用法时。冗长比提供清晰的线条更好地提供清晰的画面。问题不在优化代码上,答案试图给出一种处理此类转换的模块化方法。@ShadowRanger
parasrish

1
目的是sstream.clear();什么?该sstream对象将在作用域末端自动销毁,因此return sstream.str();可以这样做。

sstream.clear在流以作用域结束之前将只清除内容(用clear清除所有fail和eof标志)。的确,当作用域消失时,流变量的生命周期会因此sstream.str而被用于按值返回。[参考:cplusplus.com/reference/ios/ios/clear/]
悖论

2

我的解决方案。仅允许整数类型。

更新。您可以在第二个参数中设置可选的前缀0x。

定义

#include  <iomanip>
#include <sstream>

template <class T, class T2 = typename std::enable_if<std::is_integral<T>::value>::type>
static std::string ToHex(const T & data, bool addPrefix = true);



template<class T, class>
inline std::string Convert::ToHex(const T & data, bool addPrefix)
{
    std::stringstream sstream;
    sstream << std::hex;
    std::string ret;
    if (typeid(T) == typeid(char) || typeid(T) == typeid(unsigned char) || sizeof(T)==1)
    {
        sstream << static_cast<int>(data);
        ret = sstream.str();
        if (ret.length() > 2)
        {
            ret = ret.substr(ret.length() - 2, 2);
        }
    }
    else
    {
        sstream << data;
        ret = sstream.str();
    }
    return (addPrefix ? u8"0x" : u8"") + ret;
}

main.cpp

#include <definition.h>
int main()
{
    std::cout << ToHex<unsigned char>(254) << std::endl;
    std::cout << ToHex<char>(-2) << std::endl;
    std::cout << ToHex<int>(-2) << std::endl;
    std::cout << ToHex<long long>(-2) << std::endl;

    std::cout<< std::endl;
    std::cout << ToHex<unsigned char>(254, false) << std::endl;
    std::cout << ToHex<char>(-2, false) << std::endl;
    std::cout << ToHex<int>(-2, false) << std::endl;
    std::cout << ToHex<long long>(-2, false) << std::endl;
    return 0;
}

结果:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe


1

我想添加一个答案,以享受C ++语言的美丽。它的适应性可以在高低水平下工作。编程愉快。

public:template <class T,class U> U* Int2Hex(T lnumber, U* buffer)
{
    const char* ref = "0123456789ABCDEF";
    T hNibbles = (lnumber >> 4);

    unsigned char* b_lNibbles = (unsigned char*)&lnumber;
    unsigned char* b_hNibbles = (unsigned char*)&hNibbles;

    U* pointer = buffer + (sizeof(lnumber) << 1);

    *pointer = 0;
    do {
        *--pointer = ref[(*b_lNibbles++) & 0xF];
        *--pointer = ref[(*b_hNibbles++) & 0xF];
    } while (pointer > buffer);

    return buffer;
}

例子:

char buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns "0000000012345678"
Int2Hex(305419896UL, buffer);//returns "12345678"
Int2Hex((short)65533, buffer);//returns "FFFD"
Int2Hex((char)18, buffer);//returns "12"

wchar_t buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns L"0000000012345678"
Int2Hex(305419896UL, buffer);//returns L"12345678"
Int2Hex((short)65533, buffer);//returns L"FFFD"
Int2Hex((char)18, buffer);//returns L"12"

这确实使用了其他答案中未发现的某些技术。您能否编辑答案以包括其工作原理和作用的一些解释?
杰森·艾勒

0
#include <iostream> 
#include <sstream>  

int main()
{
unsigned int i = 4967295; // random number
std::string str1, str2;
unsigned int u1, u2;

std::stringstream ss;

使用空指针:

// INT to HEX
ss << (void*)i;       // <- FULL hex address using void pointer
ss >> str1;          //     giving address value of one given in decimals.
ss.clear();         // <- Clear bits
// HEX to INT
ss << std::hex << str1;   // <- Capitals doesn't matter so no need to do extra here
ss >> u1;
ss.clear();

加0x:

// INT to HEX with 0x
ss << "0x" << (void*)i;   // <- Same as above but adding 0x to beginning
ss >> str2;
ss.clear();
// HEX to INT with 0x
ss << std::hex << str2;   // <- 0x is also understood so need to do extra here
ss >> u2;
ss.clear();

输出:

std::cout << str1 << std::endl; // 004BCB7F
std::cout << u1 << std::endl;   // 4967295
std::cout << std::endl;
std::cout << str2 << std::endl; // 0x004BCB7F
std::cout << u2 << std::endl;   // 4967295


return 0;
}

-1
int var = 20;
cout <<                          &var << endl;
cout <<                     (int)&var << endl;
cout << std::hex << "0x" << (int)&var << endl << std::dec; // output in hex, reset back to dec

0x69fec4(地址)
6946500(十进制地址)0x69fec4(十进制
地址,十六进制输出)


本能地用这个...
int address =(int)&var;

在其他地方看到了...
无符号长地址= reinterpret_cast(&var);

评论告诉我这是正确的...
int address =(int)&var;

说到 光线充足,你在哪里?他们得到了太多的喜欢!


这个问题已经被很好地解决了。您的答案对已发布的内容有什么帮助?地址与地址有什么关系?
Lightness Races in Orbit

@LightnessRacesinOrbit尚未关闭吗?您是否对最近发表评论的3个人说过这句话?对于我一直在寻找的东西来说,这只是更多。它可能会帮助别人。地址与它有什么关系?谁读取十进制的地址?这是一个真实的例子。
水坑

张贴将近九年前发布的相同答案被认为没有用,并且对等式指针的这种引入似乎并非天作之合-OP并没有询问指针。此外,不,它不会是unsigned long,但std::intptr_t
轻轨比赛

intptr_t = int ... uintptr_t = unsigned int ...内存地址现在已签名吗?一个int给你多少内存?
水坑

您错过了重点。一个intptr_t可存储在构建平台上的任何指针; 这不是[必要]正确的unsigned int。同样,这些都不是问题所在。我没有进一步的回应
Lightness Races in Orbit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.