最近公司项目业务处理上需要频繁对二进制数据进行,期间涉及到很多字节顺序、BCD码、校验码等内容,时间长一些又给忘记,还要再查一次。
所以这里统一做个备忘,也顺便把这些概念牵扯到核心和作用理解清楚。
我们把一个数值写入内存,或者从内存读取数值时,内存地址一定是递增的。在该内存块存放的数值,高字节在先,还是高字节在后就对应了大、小端模式。
举例,我们需要把0x123456写入内存:
内存地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
---|---|---|---|---|
大端模式(高字节在前,低字节在后) | 0x12 | 0x34 | 0x56 | 0x78 |
小端模式(低字节在前,高字节在后) | 0x78 | 0x56 | 0x34 | 0x12 |
不同厂商的设备,在传输数据时,有的用大端模式有的用小端。导致前期人肉解读报文时特别苦逼,经常搞错。
分类 | 特点 |
---|---|
大端模式 | 符号位在所表示的数据的内存的第一个字节中,便于快速判断数据的正负和大小 |
小端模式 | 1. 内存的低地址处存放低字节,所以在强制转换数据时不需要调整字节的内容; 2.CPU做数值运算时从内存中依顺序依次从低位到高位取数据进行运算,直到最后刷新最高位的符号位,这样的运算方式会更高效 |
两者各有优缺点,彼此不分伯仲。再加上硬件厂商虽然代码一直在迭代,但数据模式牵扯太多只能在已有系统上一路坚持,因此在多字节存储顺序上始终没有一个统一的标准。
BCD码是一种存储和表示数值的方式,主要用在表示时间或者财务数据上。从上面数据传输协议截图上也能看到,不管哪家提供的协议,存储时间时一般都BCD码来表示。
BCD码有很多种表示方法,这里只记录一下最常用的8421表示法。该表示法下,记录数值时将十六进制的写法直接看做是十进制的值。
例如:
12点34分,直接用 0x12, 0x34 来记录
上面用0x12来表示12点,但其实0x12转换为十进制应该是18,所以我们需要有互转的方法来处理。
其实转换的方法也很简单,只需要分别处理十位和个位数值即可(时间不用考虑百位)
// BCD码 转 十进制
#define BCD_2_DECIMAL(x) ((((x) & 0xF0) >> 4) * 10 + ((x) & 0x0F))
// 十进制 转 BCD码
#define DECIMAL_2_BCD(x) ((((x) / 10) << 4) + ((x) % 10))
CRC16校验没有前面两个那么坑,这里主要是记录一下CRC的作用
CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。
循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,进而可以保证在软件层次上数据传输的正确性和完整性。
讲人话:
1、在网络数据传输时,发送方和接收方约定好一套数据校验的方式(比如CRC16、CRC32、奇偶校验等);
2、发送方在业务数据的最后增加校验位,并填入依据业务数据算出的校验值;
3、接收方收到数据后,依照约定的方式自行讲业务数据计算一个校验值出来并与传输数据内的校验值做比较,从而判断出数据的完整性/真实性。