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

36

我以前搜索过将char*转换为hex字符串,但是我找到的实现会在hex字符串的末尾添加一些不存在的垃圾内容。我从套接字接收数据包,并需要将它们转换为hex字符串以进行记录(空终止缓冲区)。有人能为我建议一个好的C++实现吗?

谢谢!


1
你所说的十六进制字符串是什么意思? - Dan F
你尝试修复实现了吗?你能发布一下实现和一些输入/输出吗? - dirkgently
1
“在十六进制字符串的末尾添加了一些不存在的垃圾” - 你可能将非空终止缓冲区传递到需要 LPSTR 的函数中。并不是所有 char* 都是字符串。 - Agent_L
我猜是的,您能告诉我如何从空结尾缓冲区获取十六进制吗? - Roman
可能是char[] to hex string exercise的重复问题。 - Ben Voigt
8个回答

38

假设数据是char*类型。使用std::hex的工作示例:

for(int i=0; i<data_length; ++i)
    std::cout << std::hex << (int)data[i];
或者如果你想将所有内容保存在一个字符串中:
std::stringstream ss;
for(int i=0; i<data_length; ++i)
    ss << std::hex << (int)data[i];
std::string mystr = ss.str();

24
你需要使用std:setfill和std::setw来正确地进行转换。 参见:https://dev59.com/tWsz5IYBdhLWcg3w0bSl#7639754 - oferei
4
这个答案是错误的,会导致数据损坏。请查看上面@oferei的评论中的链接以获取正确的示例。 - T.Coutlakis
char*数组元素直接转换为intunsigned int会导致超过0x7F的字节被错误地“符号扩展”。您需要先将char强制转换为uint8_t,然后将其转换为unsigned int,以正确表示字节。请参见此示例:https://stackoverflow.com/questions/62934400/ - Edward

24

这里有一些内容:

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

for( int i = data; i < data_length; ++i )
{
    char const byte = data[i];

    string += hex_chars[ ( byte & 0xF0 ) >> 4 ];
    string += hex_chars[ ( byte & 0x0F ) >> 0 ];
}

你能解释一下这是如何工作的吗? - Nam Vu
解释:每个字节(unsigned char)有8位;由于8 == 4*2,并且十六进制中的最大数字是F==15,它在二进制表示中需要4位,因此你需要用两位十六进制数来表示一个字节。代码的作用是,首先使用与运算符(logical AND)对每个字节进行位掩码操作,分别为1111 00000000 1111,以仅获取二进制数字中适合单个十六进制数字的部分;然后,如果它是二进制数字的第一个4位数字(两个数字组成的十六进制数对中的第一个数字),我们将其右移,以便将其用作0到15,然后将其用作hex_chars索引。希望能帮到你。 - Shahaboddin

14

最简单的方法:

int main()
{
    const char* str = "hello";
    for (const char* p = str; *p; ++p)
    {
        printf("%02x", *p);
    }
    printf("\n");
    return 0;
}

7
这仅适用于以空字符结尾的字符串。因此很可能会导致与他提出问题时遇到的相同问题。 - David Schwartz
在我的测试中,@K-ballo的解决方案所花费的时间更少!以纳秒为单位测量。 - Shahaboddin

12

我在这里找到了一个很好的例子C ++中显示char为十六进制字符串

  std::vector<char> randomBytes(n);
  file.read(&randomBytes[0], n);

  // Displaying bytes: method 1
  // --------------------------
  for (auto& el : randomBytes)
    std::cout << std::setfill('0') << std::setw(2) << std::hex << (0xff & (unsigned int)el);
  std::cout << '\n';

  // Displaying bytes: method 2
  // --------------------------
  for (auto& el : randomBytes)
    printf("%02hhx", el);
  std::cout << '\n';
  return 0;

如上所示,方法1可能更符合C++的风格:

将其强制转换为无符号整数
使用std::hex表示值为十六进制数字
使用来自<iomanip>std::setwstd::setfill进行格式化
请注意,您需要掩码强制转换后的整数与0xff进行按位与运算,以显示最低有效字节:
(0xff & (unsigned int)el)

否则,如果设置了最高位,则强制转换将导致三个最高有效字节被设置为ff


吹毛求疵 - 方法1应该使用static_cast(关于更C++的方式) - Class Skeleton
如果使用std::vector<unsigned char>(对于随机字节数组可能更好一些),那么您就不需要0xff&部分。 - teeks99

7

上面的代码片段提供了错误的字节顺序,因此我稍作修正。

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

std::string byte_2_str(char* bytes, int size) {
  std::string str;
  for (int i = 0; i < size; ++i) {
    const char ch = bytes[i];
    str.append(&hex[(ch  & 0xF0) >> 4], 1);
    str.append(&hex[ch & 0xF], 1);
  }
  return str;
}

3
这可以是对K-ballo答案的评论,也可以作为回答(并且你可以提到你修复了什么问题)。请进行编辑。 - dirkgently
你能解释一下这是如何工作的吗? - Nam Vu

5

使用 boost 库:

#include <boost/algorithm/hex.hpp>

std::string s("tralalalala");
std::string result;
result.reserve(s.size() * 2);
boost::algorithm::hex_lower(s, std::back_inserter(result));

https://godbolt.org/z/jEc1vPW38


为什么boost::algorithm::hex函数总是将字符转换为大写?如何使其不改变大小写? - polapts

0
您可以尝试使用以下代码将数据包中的字节转换为以空字符结尾的字符串,并存储到“string”变量中进行处理。
const int buffer_size = 2048;
// variable for storing buffer as printable HEX string
char data[buffer_size*2];
// receive message from socket
int ret = recvfrom(sock, buffer, sizeofbuffer, 0, reinterpret_cast<SOCKADDR *>(&from), &size);
// bytes converting cycle
for (int i=0,j=0; i<ret; i++,j+=2){ 
    char res[2]; 
    itoa((buffer[i] & 0xFF), res, 16);
        if (res[1] == 0) {
            data[j] = 0x30; data[j+1] = res[0];
        }else {
            data[j] = res[0]; data[j + 1] = res[1];
        }
}
// Null-Terminating the string with converted buffer
data[(ret * 2)] = 0;

当我们发送十六进制字节0x01020E0F的消息时,变量"data"包含字符串"01020e0f"的字符数组。


-5
你可以使用 std::hex
例如。
std::cout << std::hex << packet;

8
我不知道你对于std::hex对于char*输出会有什么看法,但你应该构建一个可运行的演示程序。 - Ben Voigt

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