C语言实现CRC校验
要实现C语言中的CRC校验,你可以按照以下步骤进行操作:
-
首先,确定所使用的CRC算法和参数(比如CRC-16、CRC-32等)以及多项式(生成多项式)的值。
-
创建一个CRC查找表(Table),用于存储预先计算好的CRC值。根据所选择的CRC算法和参数,表格的大小会有所不同。
-
给定待校验的数据(比如一个字节数组),初始化一个CRC寄存器为初始值(通常为全1或全0)。
-
对每个字节进行以下操作:
a) 将当前字节与CRC寄存器的最高位对齐。
b) 通过查找表,将CRC寄存器的值与当前字节进行XOR运算。
c) 将CRC寄存器向左移动一个字节,并将结果与查找表中的值进行XOR运算。 -
处理完所有字节后,CRC寄存器中的值即为校验结果。
下面是一个简单的示例代码,演示了如何实现CRC-16校验:
#include <stdio.h>unsigned short crc16_ccitt(unsigned char *data, int len) {unsigned short crc = 0xFFFF;unsigned short lookup_table[256] = {// CRC-16/CCITT lookup table// ...};for (int i = 0; i < len; i++) {crc = (crc << 8) ^ lookup_table[(crc >> 8) ^ data[i]];}return crc;
}int main() {unsigned char data[] = {0x12, 0x34, 0x56, 0x78};int data_len = sizeof(data) / sizeof(data[0]);unsigned short crc = crc16_ccitt(data, data_len);printf("CRC-16 result: %04X\n", crc);return 0;
}
对于16位循环冗余效验(CRC-16),CRC结果为单字,其低字节在前,高字节在后。其生成步骤大致如下:
-
设置一个16位的CRC寄存器,并赋以初值0xFFFF
-
将数据帧中的第一个字节,与CRC寄存器的低8位按位异或,并保存在CRC寄存器中
-
将CRC寄存器右移1位,并检测移出的最低位是否为1,如果最低位为1,则将CRC寄存器与固定数0xA001异或
-
重复步骤3共8次
-
对数据帧的下一个字节重复步骤2,3,4,直到数据域的最后一个数据
-
最后的CRC寄存器中的内容,就是最后的效验值,将其附加在数据帧的最后一个数据之后,并保持低8位在前,高8位在后的放置。
#include <stdio.h>
typedef unsigned short Uint16;
int main()
{ Uint16 crc;crc=0xffff;char a[6]={0x01,0x03,0x00,0x00,0x00,0x0a};char *buf;buf=&a[0];unsigned char i,j,check;for( i=0; i<6; i++){crc =crc^*buf;for(j=0; j<8; j++){check = crc&1;crc = crc>>1;crc = crc&0x7fff;if(check) crc =crc^0xa001;}buf++; }printf("%x",crc);return 0;
}
要实现C语言中的CRC-32校验,你可以按照以下步骤进行操作:
-
首先,确定使用的CRC算法和参数,这里是CRC-32。
-
创建一个CRC查找表(Table),用于存储预先计算好的CRC值。根据所选择的CRC算法和参数,表格的大小会有所不同。
-
给定待校验的数据(比如一个字节数组),初始化一个CRC寄存器为初始值(通常为全1或全0)。
-
对每个字节进行以下操作:
a) 将当前字节与CRC寄存器的最高位对齐。
b) 通过查找表,将CRC寄存器的值与当前字节进行XOR运算。
c) 将CRC寄存器向左移动一个字节,并将结果与查找表中的值进行XOR运算。 -
处理完所有字节后,CRC寄存器中的值即为校验结果。
下面是一个简单的示例代码,演示了如何实现CRC-32校验:
#include <stdio.h>unsigned int crc32(unsigned char *data, int len) {unsigned int crc = 0xFFFFFFFF;unsigned int lookup_table[256] = {// CRC-32 lookup table// ...};for (int i = 0; i < len; i++) {crc = (crc >> 8) ^ lookup_table[(crc ^ data[i]) & 0xFF];}return ~crc;
}int main() {unsigned char data[] = {0x12, 0x34, 0x56, 0x78};int data_len = sizeof(data) / sizeof(data[0]);unsigned int crc = crc32(data, data_len);printf("CRC-32 result: %08X\n", crc);return 0;
}
CRC-32常用(事实标准)检验函数针对能够从硬件上进行比特流实时计算而设计,即每个数据的一位进来后马上就能进行CRC-32,而不必收全数据再计算。因此对应的软件CRC-32存在一些特点:
初始值预设为0xFFFFFFFF
针对数据字节的低位先传输场景,因此数据字节的低位是高优先处理的
按照字节分段进行CRC-32计算,字节放在寄存器的低字节,因此字节最低位在左高由低的最右边一位,在进行CRC计算过程时,要从最低位/最右侧位置开始判断,移位时向右移出。因为校验码高冥端也要相应对齐,所以检验码也就要做倒位序,如0x04C11DB7(0000 0100 1100 0001 0001 1101 1011 0111)倒序为了0xEDB88320(1110 1101 1011 1000 1000 0011 0010 0000)
输出异或0xFFFFFFFF
CRC-32常用(事实标准)校验函数为反向算法(反向算法是从由右向左计算,也即计算过程中移位时,向右移出。)
uint32_t PY_CRC_32_M(uint8_t *di, uint32_t len)
{uint32_t crc_poly = 0xEDB88320; //Inversion bit sequence of 0x04C11DB7uint32_t data_t = 0xFFFFFFFF; //initial valuefor(uint32_t i=0; i<len; i++){data_t ^= di[i];for (int8_t j = 8; j > 0; --j){data_t = (data_t >> 1) ^ ((data_t & 1)? crc_poly: 0);}}return data_t ^ 0xFFFFFFFF;
}