如何在C++中将整数转换为十六进制字符串?
我可以找到一些方法来做到这一点,但它们大多似乎针对C语言。似乎在C++中没有本地方式来实现它。不过这是一个非常简单的问题;我有一个int
,我想将其转换为十六进制字符串以便稍后打印。
对于固定的数字位数,例如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
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"
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
C++ 文件
#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::format
和fmt::format("{:x}", value)
相比,对于大于(1ll << 60)的值,我获得了2倍的速度,对于较小的值,我获得了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"},
};
#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;
}
您可以使用此模板函数
template <class T>
std::string IntToHexForm(T a)
{
std::string res;
for (int i = 0; i < sizeof(T); i++)
{
int lowByte = a % 16;
a /= 16;
int highByte = a % 16;
a /= 16;
if (highByte > 9)
res = std::string(1, 'a' + highByte - 10) + res;
else
res = std::to_string(highByte) + res;
if (lowByte > 9)
res = std::string(1, 'a' + lowByte - 10) + res;
else
res = std::to_string(lowByte) + res;
}
return res;
}
您可以使用不同的整数调用它,例如:
IntToHexForm(10)
将返回 00000010IntToHexForm((unsigned char)10)
将返回 10