C++十六进制解析

11

我想知道如何将十六进制字符串转换为人类可读的字符串(如果有意义的话)。这是我第一次真正接触十六进制值,所以我仍在学习如何处理它们。

我有一个程序正在从包含原始数据(十六进制)的文件中读取数据,我需要解析这些信息使其变得人类可读。

我需要做的一个示例就像这个网站所做的那样:http://home2.paulschou.net/tools/xlate/,您可以输入十六进制并将其转换为文本。


1
澄清一下:您想将二进制数据以十六进制格式显示出来吗? - James
我想要将以十六进制存储的原始数据包数据转换为人类可读格式。 - Undawned
我需要将数据转换为其真实值,该数据的格式类似于:0000008f74d89d0fe4caca7f585f35049。 - Undawned
我所提到的网站部分是你可以输入十六进制数据并点击解码/转换按钮,然后在文本格式中查看它的部分。数据输入的一个示例是:0000008f74d89d0fe4caca7f585f35049,我想看到的是从十六进制数据转换而来的文本数据,例如“我的名字是弗兰克”。我没有任何源代码,因为我还没有找出如何做到这一点,我很难正确地解释它 =(. - Undawned
这不是一个非常有用的问题。也许有人可以弄清楚他实际想要什么,并重新措辞问题? - lmat - Reinstate Monica
显示剩余3条评论
4个回答

12

C++字符串工具库(StrTk)库中获取,以下内容应该足够。请注意,out应指向一个大小为std::distance(begin,end)一半的内存块,并且[begin,end)范围内的值应为0-9A-F或0-9a-f。

inline bool convert_hex_to_bin(const unsigned char* begin, 
                               const unsigned char* end, 
                               unsigned char* out)
    {
       if (std::distance(begin,end) % 2)
          return false;
       static const std::size_t symbol_count = 256;
       static const unsigned char hex_to_bin[symbol_count] = {
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2F
                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
                    0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3F
                    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x40 - 0x47
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5F
                    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x60 - 0x67
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9F
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 - 0xA7
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 - 0xAF
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0 - 0xB7
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 - 0xBF
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 - 0xC7
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 - 0xCF
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 - 0xD7
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 - 0xDF
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 - 0xE7
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 - 0xEF
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 - 0xF7
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 0xF8 - 0xFF
                  };

       const unsigned char* itr = begin;
       while (end != itr)
       {
          (*out)  = static_cast<unsigned char>(hex_to_bin[*(itr++)] << 4);
          (*out) |= static_cast<unsigned char>(hex_to_bin[*(itr++)]     );
          ++out;
       }
       return true;
    }

4
获取给定数字的十六进制表示的C++方式是使用流的hex修饰符,例如以下示例:
const int i = 0xdeadbeef;
cout << "0x" << hex << i << endl; // prints "0xdeadbeef"

您可以在字符串流上使用相同的修饰符,以便在字符串变量中获取十六进制表示形式。
const int i = 0xdeadc0de;
ostringstream stream;
stream << "0x" << hex << i;

const string s = stream.str(); // s now contains "0xdeadc0de"

更新:
如果您的输入数据以包含字符串字符的十六进制表示形式的字符串形式给出,则需要知道输入字符串的编码才能正确显示它。在最简单的情况下,该字符串类似于ASCII,将一个字节映射到一个字符。因此,在给定的输入“414243”中,每两个字符(“41”,“42”,“43”)映射到一个ASCII值(65、66、67),这些值映射到一个字符(“A”,“B”,“C”)。
以下是如何在C++中实现:
const string hexData = "414243";

assert( hexData.size() % 2 == 0 );

ostringstream asciiStream;
istringstream hexDataStream( hexData );
vector<char> buf( 3 ); // two chars for the hex char, one for trailing zero
while ( hexDataStream.good() ) {
    hexDataStream.get( &buf[0], buf.size() );
    if ( hexDataStream.good() ) {
        asciiStream << static_cast<char>( std::strtol( &buf[0], 0, 16 ) );
    }
}

const string asciiData = asciiStream.str(); // asciiData == "ABC"

使用中的std::strtol函数可以轻松实现;如果您坚持使用模板类来执行此操作,请使用std::stringstream将单个子字符串(例如“41”)转换为十进制值(65)。

1
我有点困惑,似乎这只是将十六进制数据存储到字符串中?我需要从十六进制数据转换为可读的字符串,就像 http://home2.paulschou.net/tools/xlate/ 这种网站所做的那样。 - Undawned
它给出了一个数字的十六进制表示,对吧。你所说的“十六进制数据”是什么意思?输入数据是一个带有字符“414243”的字符串,你想将其转换为例如“ABC”(因为这就是该网站所做的)吗? - Frerich Raabe
是的,我想将它转换为“ABC”。这个1062000000000002000100024177616b656e65642d4465760036372e3232382e35302e3232333a38303835000000000009022c010000576f575472616e63652d4177616b656e696e670036372e3232382e34392e39303a3830383500000000000a包含一些字符串和服务器的IP地址,我希望能够将上述数据转换为一种格式,以便我可以读取它所持有的值。 - Undawned
这与我之前尝试的类似,但由于某种原因它产生了相同的结果,当打印回来时似乎只显示了前两个字符,我不确定为什么字符串的长度明显大于打印出来的内容。我解析的数据是否包含终止字符干扰了输出? - Undawned
如果我在我的更新代码中使用你评论中的(长)示例字符串,我确实可以看到一些字符串和一个IP地址。我只是使用了我的上面的代码,并在结尾处添加了“cout << asciiData << endl;”。也许你正在使用C API来打印字符串,第三个“00”字节(一个NULL字节!)终止了字符串输出。 - Frerich Raabe
哦,没错,这个方法可行,我在输出时使用了“.c_str()”,非常感谢,这将帮助我推进我的应用程序 =)。 - Undawned

0

十六进制是一种显示二进制数据的方式。正如你所说,它不是“原始数据”。如果你拥有的原始数据包含一个字符串,当你将其输出到屏幕上时,你应该能够看到这个字符串(可能还有其他垃圾信息)。

下面是一个循环,用于打印数据块中的ASCII字符。要获取其他内容,你需要处理它的格式。

char *binary_data[ BUFFER_SIZE ];
size_t len = BUFFER_SIZE;
len = get_a_packet( data, len ); // or however you get data

for ( char *text_ptr = binary_data; text_ptr != binary_data + len; ++ text_ptr ) {
    if ( * text_ptr <= '~' && * text_ptr >= ' ' ) { // if it's ascii
        cerr << * text_ptr; // print it out
    }
}

cerr << endl;

这不是问题的答案,你试图找到ASCII字符并显示它。为什么在读取字符时要分配指针缓冲区?为什么要尝试将此指针数组的地址分配给char指针(不应编译)?为什么要使用错误输出? - harper
@Harper:我认为他对二进制数据的本质感到困惑,实际上他没有将文本数据编码为十六进制ASCII。要打印您正在以其他程序查看为十六进制的某些数据的文本部分,您需要跳过非ASCII字符。指针缓冲区是一个笔误,应该是普通的char缓冲区。错误输出是因为我将这种事情与调试相关联,并且我使用cerr进行调试,以避免干扰程序的“真实”输出。 - Potatoswatter

0
fprintf(file, "%h", thing);

类似这样的东西?


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