2012-01-10 44 views
1

我最近被分配到一个C++项目,涉及通过UDP在计算机之间发送的信息。当数据包到达时,我有一个接受数据的程序,并可以将它显示为原始十六进制字符串。然而,我正在努力掌握整个过程应该如何工作。据推测,十六进制字符串包含多个字段(例如,一个4字符数组,一些float_32s和一些uint_32s)。搞清楚网络,十六进制和ascii如何交互

如何将该字符串的部分转换为正确的变量类型?第一个值,一个ASCII标题,很简单,十六进制字符串中的前八个字符是ASCII字的十六进制表示(十六进制可以直接翻译为大写字母E)。但是下一个值,一个32位浮点数,对我来说并没有什么意义。十六进制值“42 01 33 33”和浮点值“32.3”(给出的例子)之间的关系是什么?

我在这里有点累赘,我觉得我错过了关于数字系统工作方式的一些重要信息。

+2

“十六进制字符串”只是“原始”。相反,它是原始二进制数据的十六进制*表示*。阅读[float format](http://en.wikipedia.org/wiki/Single-precision_floating-point_format)了解它如何适合四个字节。 – 2012-01-10 22:33:20

回答

2

C中的所有类型都有一个表示(对于大多数类型来说,它是由特定的实现定义的)。大多数C实现使用IEEE 754来表示浮点类型(这实际上可能是C和C++的一个需求,但是从内存中它不是)。维基百科文章解释了如何在内存中表示浮点类型。在大多数C和C++实现中,float是32位类型,double是64位类型。因此,在这些实现中,float是4个字节宽,并且double是8个字节宽。

要小心,因为字节顺序可能不同。一些体系结构将浮动类型存储为小端,一些以大端存储。还有一篇关于endianness的维基百科文章。

要将字节复制到浮动类型,您必须确保浮动类型的大小与您拥有的字节数相同,然后您可以逐个复制字节‘到’浮动式。像这样的东西会给你它的要点:

unsigned char rep[] = { 0x42, 0x01, 0x33, 0x33 }; 
float someFloat; 

if (sizeof(someFloat) == 4) 
{ 
    memcpy(&someFloat, rep, sizeof(someFloat)); 
} 
else 
{ 
    // throw an exception or something 
} 

有复制字节浮动类型的其他方式,但要小心‘打破规则’(类型双关等)。另外,如果结果值不正确,可能是因为字节顺序错误,因此需要将字节反向复制,以便表示形式的第4个字节是浮点数的第1个字节。

+0

这段代码给了我奇怪的结果;根据我的调试器,'someFloat'的值为4.1667829e-008,当我尝试使用myStr.Format(“%f”,someFloat)将其粘贴到CString中时,它始终打印为“0.000000”。 – Andrew 2012-01-11 19:19:56

+0

AHA!我需要仔细阅读,正如你所建议的那样,问题在于字节顺序错误。我使用了{0x33,0x33,0x01,0x42}并得到了32.299999!谢谢! – Andrew 2012-01-11 19:35:29

1

如果你有一个十六进制值:

42 01 33 33 

这是

0100 0010 0000 0001 0011 0011 0011 0011 

二进制代码的等价物。

现在有一个名为IEEE 754的浮点标准,它告诉你如何将浮点数格式化为二进制或后面的格式。

它的要点是第一位是符号(正数/负数),接下来的8位是指数,最后23位是mantisse。这是计算机内部保存浮点数的方式,因为它只能存储1和0。

如果以IEEE指定的方式将它们加在一起,则得到32.3。

0

确切数据格式由所使用的协议所指定,但共同的方式来表示数字数据是:

无符号整数:这实际上是最简单的。其典型的表示原则上与我们的正常十进制系统一样工作,除了“数字”是字节,并且可以具有256个不同的值。

如果你看看像3127这样的十进制数,你会看到三位数字。最不重要的数字是最后一个数字(在这种情况下是7)。最不重要的意思是,如果您将其更改为1,您将获得最小的值更改(即1)。示例中最重要的数字是最左边的数字3:如果您将该数字更改为1,则会对数值进行最大更改,即更改为1000.由于有10个不同的数字(0到9),因此,由“3127”表示的数字是3 * 10 * 10 * 10 + 1 * 10 * 10 + 2 * 10 + 7。请注意,itz只是最重要的数字第一位的约定;你也可以定义最低有效位数字先出现,然后这个数字将被写为“7213”。

现在在大多数编码中,无符号数字的工作原理完全相同,除了“数字”是字节,因此而不是基数为10的基数为256.此外,与十进制数不同,重要字节(MSB)或最低有效字节(LSB)首先出现;两种约定都以不同的协议或文件格式使用。例如,在MSB优先(也称为big-endian编码)的4字节(即32位)无符号整数中,值1000 = 0 * 256^3 + 0 * 256^2 + 3 * 256 + 232将由四个字节值0, 0, 3, 232或十六进制00 00 03 E8表示。对于little-endian编码(首先是LSB),代之以。而作为16位整数,它只是03 E8(大端)或E8 03(小端)。

对于有符号整数,最常用的表示形式是二进制补码。基本上这意味着如果最高有效位是1(即最高有效字节是128或更大),则字节序列不会像上面所写的那样对数字进行编码,而是通过减去2 ^(位)从它开始,其中(位)是数字中的位数。例如,在一个有符号的16位int中,序列FF FF不是65535,因为它将在16位无符号整型中,而是65535-2^16 = -1。与未签名的整数一样,您必须区分大端和小端。例如,-3将是16位位端的FF FD,而16位的小端是FD FF

浮点比较复杂一点,今天通常使用IEEE/IEC规定的格式。基本上,浮点数的形式是符号*(1.mantissa)* 2 ^指数,符号,尾数和指数存储在不同的子域中。再次,有小端和大端形式。