繁体   English   中英

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

[英]Integer to hex string in C++

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

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

使用<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 this 来规避问题:

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();
}

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

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;
}

您可以使用 C++20 std::format来做到这一点:

std::string s = std::format("{:x}", 42); // s == 2a

std::format广泛可用之前,您可以使用{fmt} 库std::format基于( godbolt ):

std::string s = fmt::format("{:x}", 42); // s == 2a

免责声明:我是 {fmt} 和 C++20 std::format的作者。

使用std::stringstream将整数转换为字符串,并使用其特殊的操作符来设置基数。 例如像这样:

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

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

int i = /* ... */;
std::cout << std::hex << i;
#include <boost/format.hpp>
...
cout << (boost::format("%x") % 1234).str();  // output is: 4d2

您可以尝试以下方法。 它正在工作...

#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;
}

从 C++20 开始,使用std::format ,您可以这样做:

std::format("{:#x}", your_int);    // 0x2a
std::format("{:#010x}", your_int); // 0x0000002a

演示

看看我的解决方案, [1]我逐字[2]从我的项目中复制。 我的目标是在我的实际需求中结合灵活性和安全性: [3]

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

/// Convert integer value `val` to text in hexadecimal format.
/// The minimum width is padded with leading zeros; if not 
/// specified, this `width` is derived from the type of the 
/// argument. Function suitable from char to long long.
/// Pointers, floating point values, etc. are not supported; 
/// passing them will result in an (intentional!) compiler error.
/// Basics from: 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]只有德语 API 文档被翻译成英语。
[3]翻译成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");
// width deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012");

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

以下答案在编译时正确处理 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 的回答很棒。 但稍加添加有助于捕获使用没有意义的模板参数(例如浮点数)或会导致混乱的编译器错误(例如用户定义的类型)调用此函数的情况。

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 的调用,因为到std::stringstream的 8 位整数类型(例如传递的std::uint8_t值)被视为 char,它不会给你想要的结果。 将此类整数传递给std::to_string可以正确处理它们,并且在使用其他更大的整数类型时不会造成伤害。 当然,在这些情况下您可能会受到轻微的性能影响,因为 std::to_string 调用是不必要的。

注意:我只是在对原始答案的评论中添加了这个,但我没有代表发表评论。

一种新的 C++17 方式:来自<charconv>std::to_chars ( https://en.cppreference.com/w/cpp/utility/to_chars ):

char addressStr[20] = { 0 };
std::to_chars(std::begin(addressStr), std::end(addressStr), address, 16);
return std::string{addressStr};

这有点冗长,因为std::to_chars使用预先分配的缓冲区来避免动态分配,但这也可以让您优化代码,因为如果这是在热点中分配会变得非常昂贵。

对于额外的优化,您可以省略预初始化缓冲区并检查to_chars的返回值以检查错误并获取写入数据的长度。 注意: to_chars不写空终止符!

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

我愿意:

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

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

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

您可以在https://replit.com/@JomaCorpFX/ToHex上测试/运行

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

定义.h

#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 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;
}

主文件

#include <iostream>
#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

输出

我想添加一个答案来享受 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"

我可以看到其他人用作答案的所有精心编写的编码示例,但是在 C++ 应用程序中简单地使用它并没有错:

    printf ("%04x", num);

对于数字 = 128:

    007f

https://en.wikipedia.org/wiki/Printf_format_string

C++ 实际上是经过扩展的原始 C 语言,因此 C 中的任何内容也是完全有效的 C++。

对于那些发现许多/大部分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);

供您参考的代码:

#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;
}

对于固定位数,例如 2:

    static const char* digits = "0123456789ABCDEF";//dec 2 hex digits positional map
    char value_hex[3];//2 digits + terminator
    value_hex[0] = digits[(int_value >> 4) & 0x0F]; //move of 4 bit, that is an HEX digit, and take 4 lower. for higher digits use multiple of 4
    value_hex[1] = digits[int_value & 0x0F]; //no need to move the lower digit
    value_hex[2] = '\0'; //terminator

您还可以编写一个 for 循环变体来处理可变数字量

好处:

  • 速度:这是一个最小的位操作,没有外部函数调用
  • 内存:它使用本地字符串,不分配函数堆栈帧,不需要释放内存。 无论如何,如果需要,您可以使用字段或全局变量来使 value_ex 保持在堆栈帧之外

_itoa_s

char buf[_MAX_U64TOSTR_BASE2_COUNT];
_itoa_s(10, buf, _countof(buf), 16);
printf("%s\n", buf);    // a

swprintf_s

uint8_t x = 10;
wchar_t buf[_MAX_ITOSTR_BASE16_COUNT];
swprintf_s(buf, L"%02X", x);

另一种简单的方法

#include<iostream> 
#include<iomanip> // for setbase(), works for base 8,10 and 16 only
using namespace std;


int main(){
  int x = (16*16+16+1)*15;
  string ans;


  stringstream ss;
  ss << setbase(16) << x << endl;
  ans = ss.str();


  cout << ans << endl;//prints fff

使用变量:

char selA[12];

然后:

snprintf(selA, 12, "SELA;0x%X;", 85);

将导致selA包含字符串SELA;0x55;

请注意,围绕55的内容只是与我的应用程序中使用的串行协议相关的细节。

#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;
}

char_to_hex 返回一个由两个字符组成的字符串

const char HEX_MAP[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

char replace(unsigned char c)
{
    return HEX_MAP[c & 0x0f];
}

std::string char_to_hex(unsigned char c)
{
    std::string hex;

    // First four bytes
    char left = (c >> 4);
    // Second four bytes
    char right = (c & 0x0f);

    hex += replace(left);
    hex += replace(right);

    return hex;
} 

这个问题很老了,但我认为给出的答案不是最好的。 如果您使用的是 C++20,那么您可以选择使用std::format ,这是一个非常好的解决方案。 但是,如果您使用的是 C++11/14/17 或更低版本,您将没有此选项。

大多数其他答案要么使用std::stringstream ,要么实现自己的转换,直接自己修改底层字符串缓冲区。 第一种选择是相当重的。 第二种选择本质上是不安全且容易出错的。

因为我最近必须实现一个整数到十六进制字符串,所以我选择使用函数重载和模板部分特化来做一个真正的 C++ 安全实现,让编译器处理类型检查。 该代码使用sprintf (其中一种风格通常被标准库用于std::to_string )。 它依赖于模板偏特化来正确选择正确的sprintf格式和前导 0 加法。 它针对不同的操作系统和体系结构分别正确地处理不同的指针大小和unsigned long大小。 (4/4/4、4/4/8、4/8/8)

这个答案针对 C++11

H 文件:

#ifndef STRINGUTILS_H_
#define STRINGUTILS_H_

#include <string>

namespace string_utils
{
    /* ... Other string utils ... */
    
    std::string hex_string(unsigned char v);
    std::string hex_string(unsigned short v);
    std::string hex_string(unsigned int v);
    std::string hex_string(unsigned long v);
    std::string hex_string(unsigned long long v);
    std::string hex_string(std::ptrdiff_t v);

} // namespace string_utils

#endif

CPP 文件

#include "stringutils.h"

#include <cstdio>

namespace
{
    template <typename T, int Width> struct LModifier;

    template <> struct LModifier<unsigned char, sizeof(unsigned char)>
    {
        static constexpr char fmt[] = "%02hhX";
    };
    template <> struct LModifier<unsigned short, sizeof(unsigned short)>
    {
        static constexpr char fmt[] = "%04hX";
    };
    template <> struct LModifier<unsigned int, sizeof(unsigned int)>
    {
        static constexpr char fmt[] = "%08X";
    };
    template <> struct LModifier<unsigned long, 4>
    {
        static constexpr char fmt[] = "%08lX";
    };
    template <> struct LModifier<unsigned long, 8>
    {
        static constexpr char fmt[] = "%016lX";
    };
    template <> struct LModifier<unsigned long long, sizeof(unsigned long long)>
    {
        static constexpr char fmt[] = "%016llX";
    };
    template <> struct LModifier<std::ptrdiff_t, 4>
    {
        static constexpr char fmt[] = "%08tX";
    };
    template <> struct LModifier<std::ptrdiff_t, 8>
    {
        static constexpr char fmt[] = "%016tX";
    };

    constexpr char LModifier<unsigned char, sizeof(unsigned char)>::fmt[];
    constexpr char LModifier<unsigned short, sizeof(unsigned short)>::fmt[];
    constexpr char LModifier<unsigned int, sizeof(unsigned int)>::fmt[];
    constexpr char LModifier<unsigned long, sizeof(unsigned long)>::fmt[];
    constexpr char LModifier<unsigned long long, sizeof(unsigned long long)>::fmt[];
    constexpr char LModifier<std::ptrdiff_t, sizeof(std::ptrdiff_t)>::fmt[];

    template <typename T, std::size_t BUF_SIZE = sizeof(T) * 2U> std::string hex_string_(T v)
    {
        std::string ret(BUF_SIZE + 1, 0);
        std::sprintf((char *)ret.data(), LModifier<T, sizeof(T)>::fmt, v);
        return ret;
    }
} // anonymous namespace

std::string string_utils::hex_string(unsigned char v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned short v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned int v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned long v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned long long v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(std::ptrdiff_t v)
{
    return hex_string_(v);
}

我读到的所有答案都很慢,除了其中一个,但那个只适用于小端 CPU。 这是一个适用于大端和小端 CPU 的快速实现。

std::string Hex64(uint64_t number)
{
    static const char* maps = "0123456789abcdef";

    // if you want more speed, pass a buffer as a function parameter and return an std::string_view (or nothing)
    char  buffer[17]; // = "0000000000000000"; // uncomment if leading 0s are desired
    char* c          = buffer + 16;
    do
    {
        *--c = maps[number & 15];
        number >>= 4;
    }
    while (number > 0);

    // this strips the leading 0s, if you want to keep them, then return std::string(buffer, 16); and uncomment the "000..." above
    return std::string(c, 16 - (c - buffer));
}

std::formatfmt::format("{:x}", value)相比,我的速度在 2 倍(对于值 > (1ll << 60))和 6 倍(对于较小的值)之间。

输入/输出示例:

const std::vector<std::tuple<uint64_t, std::string>> vectors = {
    {18446744073709551615, "ffffffffffffffff"},
    { 4294967295u,         "ffffffff"},
    { 16777215,            "ffffff"},
    { 65535,               "ffff"},
    { 255,                 "ff"},
    { 16,                  "10"},
    { 15,                  "f"},
    { 0,                   "0"},
};

`

char sw(int num){
   char h[16] = {'0','1','2','3','4','5','6','7','8','9','a','b',' c','d','e','f'};
   return h[num];
}

String to_hexa(int num) {
  int i, j, exp = 0, temp = num;
  String hexa;
  String begin;


  while( temp >= 16 ){
    exp++;
    temp /= 16;
  }

  for ( i = 0; i <= exp; ++i){
    temp = num;
    for ( j = i; j <= exp; ++j){
      if ( j == exp ) hexa += String(sw(temp % 16));
      else temp /= 16;
    }
  }
  begin = "0x";
  for (int i=0; i < 3 - exp; i++){
    begin += "0";
  }  
  return begin + hexa;
}

`

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 地址 = (int)&var;

在别处看到这个...
无符号长地址 = reinterpret_cast(&var);

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

说到覆盖良好的轻盈,你在哪里? 他们得到了太多的赞!

您可以定义MACRO以用作这样的一个衬垫。

#include <sstream>
#define to_hex_str(hex_val) (static_cast<std::stringstream const&>(std::stringstream() << "0x" << std::hex << hex_val)).str()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM