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

210

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

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

28个回答

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

8
恰恰相反,请在“int”类型上测试您的建议;) - Kornel Kisielewicz
12
std::showbase 会显示一个 0x 前缀... - quaylar
30
警告:这将不适用于单字节,因为char始终被视为char。 - ov7a
9
你需要添加 #include <sstream>。 - David Gausmann
3
如果我要格式化多个整数,似乎每个整数都需要将 std::setw 输出到流中,而 std::hexstd::setfillstd::uppercase 等只需要发送一次到输出流中。这看起来不一致? - wcochran
显示剩余7条评论

75
你可以使用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的作者。


我们如何为此添加填充和/或正确的0x(十六进制)或0o(八进制)前缀?例如,如果我想要0x002a0o52,应该怎么做? - 0xdeadbeef
1
填充、前缀等是格式说明符的语法选项,详细描述在这里:https://fmt.dev/latest/syntax.html。对于0x002a,您可以使用"{:#06x}";对于0o52,您可以使用"0o{:o}"。这种语法非常丰富和灵活。 - undefined

59
为了使其更轻量快捷,我建议使用直接字符串填充。
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也可以吗? - S.R
@S.R 它适用于整数类型,不适用于 doublefloat(也不适用于指针) - Wolf
这是一种非常实用(但有效)的C和C++混合,关于速度我不太确定...对于我的口味来说,有点密集。 - Wolf
1
谢谢,非常棒的答案。仅仅为了做这个而引入一个流库似乎有些浪费。 - DeveloperChris
1
这会打印出 0000FFFF 作为 0xFFFF 的输出。我更喜欢将 0xFFFF 作为输出。 - jaques-sam
@DrumM 把4传递到hex_len参数里面,是吗? - Plater

34

使用 std::stringstream 将整数转换为字符串,并使用其特殊操作符来设置进制。例如:

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

20

将其作为十六进制数打印:

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

31
如果不使用std::cout<<std::hex<<i<<std::dec;,那么后面流出的所有整数都将是十六进制的。对于使用stringstream的其他答案则不需要这样做,因为流在使用后会被丢弃,但cout会一直存在。 - Mark Lakata

13

C++20引入了std::format,你可以这样使用:

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

演示


11
#include <boost/format.hpp>
...
cout << (boost::format("%x") % 1234).str();  // output is: 4d2

1
头文件是 #include <boost/format.hpp> - Wade Wang
2
Boost 没有预装,这就是为什么。 - Haseeb Mir

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
一个不错的答案,但要注意在C++11中to_stringstd命名空间的一部分。 - Alexander Oh
@Alex 是的,毕竟现在已经是2014年了...天哪,我们很快就要开始处理C++14了。 - Alex

7
一种新的 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不会写入空终止符!

6

请看一下我的解决方案[1],这是我直接从项目中复制的。我的目标是在满足实际需求的同时,结合灵活性和安全性:[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: https://dev59.com/Qm435IYBdhLWcg3w-1V_#5100745
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");

1
可以使用例如 TEST_ASSERT(int_to_hex(short(0x12)) == "0012"); 来展示宽度推断。 - Lightness Races in Orbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接