【发布时间】:2011-07-03 07:27:50
【问题描述】:
如何将C++ 中的整数转换为十六进制字符串?
我可以找到一些方法来做到这一点,但它们似乎主要针对 C。在 C++ 中似乎没有本地方法可以做到这一点。这是一个非常简单的问题;我有一个int,我想将其转换为十六进制字符串以供以后打印。
【问题讨论】:
如何将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(返回十进制)。
您可能遇到的一个问题是,这会产生表示它所需的确切数字数量。您可以使用setfill 和setw 来规避问题:
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();
}
【讨论】:
int 类型上测试您的建议;)
std::setw需要为每个int输出到流中,而std::hex,std::setfill,std::uppercase,...只需要一次发送到输出流。这似乎不一致?
只需将其打印为十六进制数:
int i = /* ... */;
std::cout << std::hex << i;
【讨论】:
std::cout<<std::hex<<i<<std::dec;,否则以后流出的所有整数都将是十六进制的。对于使用 stringstream 的其他答案,您不需要这样做,因为流在使用后被丢弃,但 cout 永远存在。
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
【讨论】:
使用std::stringstream 将整数转换为字符串,并使用其特殊操作符设置基数。比如这样:
std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();
【讨论】:
您可以尝试以下方法。它正在工作......
#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;
}
【讨论】:
to_string 是 C++11 中命名空间 std 的一部分
对于那些发现许多/大部分 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);
【讨论】:
为了让它更轻更快,我建议使用直接填充字符串。
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(不适用于指针)
0xFFFF 打印0000FFFF。我更喜欢将0xFFFF 作为输出。
供您参考的代码:
#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;
}
【讨论】:
clear 和 sstream 毫无意义(无论如何,当函数在下一行返回时它将被销毁)。您可以完全避免使用命名为 hexStr 的 return sstream.str(); 而不使用 clearing 并获得相同的效果,将四行代码减少到一行。
sstream.clear(); 的目的是什么? sstream 对象在作用域结束时自动销毁,所以 return sstream.str(); 会这样做。
sstream.clear 将在流以范围结束结束之前清除内容(以清除任何失败和 eof 标志)。实际上,当作用域死亡时,流变量的生命周期,因此sstream.str 可以用于按值返回。 [参考:cplusplus.com/reference/ios/ios/clear/]
看看我的解决方案,[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");
【讨论】:
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 的回答很棒。但稍加添加有助于捕获使用没有意义的模板参数(例如 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 调用是不必要的。
注意:我会在原始答案的评论中添加此内容,但我没有代表发表评论。
【讨论】:
char 仍然会出人意料地工作(这与大多数实现中的uint8_t 和int8_t 不同(它们分别是unsigned char 和signed char))。跨度>
... && !std::is_same_v<char, T> && !std::is_same_v<bool, T> 等...
#include <boost/format.hpp>
...
cout << (boost::format("%x") % 1234).str(); // output is: 4d2
【讨论】:
#include <boost/format.hpp>
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(地址到 12 月)
0x69fec4(十进制地址,十六进制输出)
本能地接受了这个......
int 地址 = (int)&var;
在别处看到这个...
无符号长地址 = reinterpret_cast(&var);
评论告诉我这是正确的...
int 地址 = (int)&var;
speaking of well covered 轻盈,你在哪里?他们的赞太多了!
【讨论】:
unsigned long,而是std::intptr_t。
intptr_t 可以存储构建平台上的任何指针; unsigned int 并非 [必然] 如此。而且,这些都与问题无关。我没有进一步的回应
我的解决方案。只允许整数类型。
你可以在https://replit.com/@JomaCorpFX/ToHex上测试/运行
更新。您可以在第二个参数中设置可选的前缀 0x。
definition.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;
}
main.cpp
#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"
【讨论】:
#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;
}
【讨论】:
对于固定位数,例如 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 循环变体来处理可变数字量
好处:
【讨论】:
char buf[_MAX_U64TOSTR_BASE2_COUNT];
_itoa_s(10, buf, _countof(buf), 16);
printf("%s\n", buf); // a
uint8_t x = 10;
wchar_t buf[_MAX_ITOSTR_BASE16_COUNT];
swprintf_s(buf, L"%02X", x);
【讨论】:
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,您可能会这样做:
std::format("{:#x}", your_int); // 0x2a
std::format("{:#010x}", your_int); // 0x0000002a
【讨论】:
你可以用 C++20 std::format:
std::string s = std::format("{:x}", 42); // s == 2a
在std::format 广泛可用之前,您可以使用the {fmt} library,std::format 基于 (godbolt):
std::string s = fmt::format("{:x}", 42); // s == 2a
免责声明:我是 {fmt} 和 C++20 std::format 的作者。
【讨论】:
您可以像这样定义 MACRO 以用作一个衬垫。
#include <sstream>
#define to_hex_str(hex_val) (static_cast<std::stringstream const&>(std::stringstream() << "0x" << std::hex << hex_val)).str()
【讨论】: