弄清楚网络、hex和ascii是如何交互的

Figuring out how networking, hex, and ascii interact

本文关键字:何交互 交互 网络 hex ascii 弄清楚      更新时间:2023-10-16

我最近被分配到一个C++项目,该项目涉及通过UDP在计算机之间发送信息。当数据包到达时,我有一个程序可以接受数据并将其显示为原始十六进制字符串。然而,我很难准确地理解整个过程应该如何运作。据推测,十六进制字符串包含几个字段(例如,4个字符的数组、一些float_32s和一些uint_32s)。

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

我有点不知所措,我觉得我错过了一些关于数字系统工作方式的重要信息。

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

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

要将字节复制到浮动类型,必须确保浮动类型的大小与您拥有的字节数相同,然后才能逐个复制字节‘进入&rsquo的;浮动型。像这样的东西会给你它的要点:

unsigned char rep[] = { 0x42, 0x01, 0x33, 0x33 };
float someFloat;
if (sizeof(someFloat) == 4)
{
    memcpy(&someFloat, rep, sizeof(someFloat));
}
else
{
    // throw an exception or something
}

还有其他方法可以将字节复制到浮动类型,但要小心‘违反规则;(键入punning等)。此外,如果结果值不正确,可能是因为字节顺序错误,因此您需要反向复制字节,以便表示中的第4个字节是浮点的第1个字节。

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

42 01 33 33

它相当于

0100 0010 0000 0001 0011 0011 0011 0011

二进制代码。

现在,有一个叫做IEEE754的浮点标准,它告诉你如何将浮点数格式化为二进制或反格式。

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

如果你按照IEEE规定的方式把它们加在一起,你会得到32.3。

确切的数据格式由所使用的协议指定,但表示数字数据的常用方法有:

无符号整数:这实际上是最简单的。它的典型表示原理上与我们的普通十进制类似,只是"数字"是字节,可以有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优先的4字节(即32位)无符号int(也称为big-endian编码)中,值1000=0*256^3+0*256^2+3*256+232将由四字节值0, 0, 3, 232或十六进制00 00 03 E8表示。对于little-endian编码(首先是LSB),它将是E8 03 00 00。作为16位整数,它将只是03 E8(big-endian)或E8 03(little-endian)。

对于有符号整数,最常用的表示法是2的补码。基本上,这意味着如果最高有效位是1(即最高有效字节是128或更大),字节序列不会像上面写的那样对数字进行编码,而是通过从中减去2^(位)得到的负数,其中(位)是数字中的位数。例如,在有符号的16位int中,序列FF FF不是16位无符号int中的65535,而是65535-2^16=-1。与无符号整数一样,您必须区分大端序和小端序。例如,-3在16位字节序中是FF FD,但在16位小字节序中却是FD FF

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