[技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码 (2)

生成多项式为H,则一共有$2^h$种可能,代码如下:

class CalcByCrcTable { private byte[] CrcTable; private void CteateTable() { int ploy = 0b0010; CrcTable = new byte[(int)Math.Pow(2,4)]; ploy <<= 4; for (int i = 0; i < CrcTable.Length ; i++) { int data = i<<4; for (int j = 0; j < 4; j++) { if ((data & 0b10000000) == 0b10000000) { data = (data << 1) ^ ploy; } else { data <<= 1; } } CrcTable[i] = Convert.ToByte((data & 0xf0)>>4); } } public byte CalcCrc() { CteateTable(); int data = 0b10010110; byte crchigh4 = CrcTable[(data>>4)&0x0f];//用查表法先查到data的高四位1001的crc值; byte value = Convert.ToByte((data & 0x0f) ^ crchigh4);//将高四位的CRC与低四位异或,得到移位四次后的数据值; byte crc = CrcTable[value]; //在用移位后的数据值查出数据的CRC校验码; return crc; } } static void Main(string[] args) { CalcByCrcTable calcByCrcTable = new CalcByCrcTable(); byte crc = calcByCrcTable.CalcCrc(); Console.WriteLine($" CRC校验码为:" + Convert.ToString(crc, 2)); Console.ReadKey(); }

//打印结果如下

CRC校验码为:1100

可以看到与前面的计算法结果一致。

5.反向校验

上面所诉的均为正向检验(Normal),当然也有反向校验(Reversed),反向校验是将数据和生成多项式均进行了一个镜像,当然算法也需要镜像,即镜像后从右往左运算。

5.1手工计算CRC反向校验码

原二进制数据:10010110

原生成多项式:0010

正向CRC校验码:1100

镜像二进制数据:01101001

镜像生成多项式:0100

镜像算法:

crc_handle_item_xor_reversed_move_bit.png

反向CRC校验码:0011

5.2.C#代码计算CRC反向校验码 class CalcByCrcTable { private byte[] CrcTable; private void CteateReversedTable() { int ploy = 0b0100; CrcTable = new byte[(int)Math.Pow(2, 4)]; for (int i = 0; i < CrcTable.Length; i++) { int data = i; for (int j = 0; j < 4; j++) { if ((data & 1) == 1) { data = (data >> 1) ^ ploy; } else { data >>= 1; } } CrcTable[i] = Convert.ToByte((data & 0x0f)); } } public byte CalcReversedCrc() { CteateReversedTable(); int data = 0b01101001; byte crclow4 = CrcTable[data & 0x0f];//用用查表法先查到data的低四位1001的crc值; byte value = Convert.ToByte(((data>>4) & 0x0f) ^ crclow4);//将第四位的CRC与低四位异或,得到移位四次后的数据值; byte crc = CrcTable[value]; //在用移位后的数据值查出数据的CRC校验码; return crc; } } static void Main(string[] args) { CalcByCrcTable calcByCrcTable = new CalcByCrcTable(); byte crc = calcByCrcTable.CalcReversedCrc(); Console.WriteLine($" CRC反向校验码为:" + Convert.ToString(crc, 2)); Console.ReadKey(); }

//打印结果如下

CRC反向校验码为:11

6.C#查表法计算CRC16校验码 //多线程使用时请注意干扰 class CalcOnCrc16 { private ushort[] Crc16NormalTable; private ushort[] Crc16ReversedTable; private void CreateNormalCrc16Table(ushort ploy) { ushort data; Crc16NormalTable = new ushort[256]; int i, j; for (i = 0; i < 256; i++) { data = (ushort)(i << 8); for (j = 0; j < 8; j++) { if ((data & 0x8000) == 0x8000) data = Convert.ToUInt16((ushort)(data << 1) ^ ploy); else data <<= 1; } Crc16NormalTable[i] = data; } } private void CreateReversedCrc16Table(ushort ploy) { ushort data; Crc16ReversedTable = new ushort[256]; int i, j; for (i = 0; i < 256; i++) { data = (ushort)i; for (j = 0; j < 8; j++) { if ((data & 1) == 1) data = Convert.ToUInt16((ushort)(data >>1) ^ ploy); else data >>= 1; } Crc16ReversedTable[i] = data; } } /// <summary> /// 正向计算CRC16校验码 /// </summary> /// <param>校验数据</param> /// <param>生成多项式</param> /// <param>校验码初始值</param> /// <returns></returns> public ushort CalcNoemalCrc16(byte[] bytes,ushort poly,ushort crcInit) { CreateNormalCrc16Table(poly); ushort crc = crcInit; for (int i = 0; i < bytes.Length; i++) { crc = Convert.ToUInt16((ushort)(crc << 8) ^ Crc16NormalTable[((crc >> 8) & 0xff) ^ bytes[i]]); } return crc; } /// <summary> /// 反向计算CRC16校验码 /// </summary> /// <param>校验数据</param> /// <param>反向生成多项式</param> /// <param>校验码初始值</param> /// <returns></returns> public ushort CalcReversedCrc16(byte[] bytes, ushort poly, ushort crcInit) { CreateReversedCrc16Table(poly); ushort crc = crcInit; for (int i = 0; i < bytes.Length; i++) { crc = Convert.ToUInt16((ushort)(crc >> 8) ^ Crc16ReversedTable[(crc & 0xff) ^ bytes[i]]); } return crc; } } 7.C#查表法计算CRC32校验码 class CalcOnCrc32 { private uint[] Crc32NormalTable; private uint[] Crc32ReversedTable; private void CreateNormalCrc32Table(uint ploy) { uint data; Crc32NormalTable = new uint[256]; int i, j; for (i = 0; i < 256; i++) { data = (uint)(i << 24); for (j = 0; j < 8; j++) { if ((data & 0x80000000) == 0x80000000) data = Convert.ToUInt32((uint)(data << 1) ^ ploy); else data <<= 1; } Crc32NormalTable[i] = data; } } private void CreateReversedCrc32Table(uint ploy) { uint data; Crc32ReversedTable = new uint[256]; int i, j; for (i = 0; i < 256; i++) { data = (uint)i; for (j = 0; j < 8; j++) { if ((data & 1) == 1) data = Convert.ToUInt32((uint)(data >> 1) ^ ploy); else data >>= 1; } Crc32ReversedTable[i] = data; } } /// <summary> /// 正向计算CRC32校验码 /// </summary> /// <param>校验数据</param> /// <param>生成多项式</param> /// <param>校验码初始值</param> /// <returns></returns> public uint CalcNoemalCrc32(byte[] bytes, uint poly, uint crcInit) { CreateNormalCrc32Table(poly); uint crc = crcInit; for (int i = 0; i < bytes.Length; i++) { crc = Convert.ToUInt32((uint)(crc << 8) ^ Crc32NormalTable[((crc >> 24) & 0xff) ^ bytes[i]]); } return crc; } /// <summary> /// 反向计算CRC32校验码 /// </summary> /// <param>校验数据</param> /// <param>反向生成多项式</param> /// <param>校验码初始值</param> /// <returns></returns> public uint CalcReversedCrc32(byte[] bytes, uint poly, uint crcInit) { CreateReversedCrc32Table(poly); uint crc = crcInit; for (int i = 0; i < bytes.Length; i++) { crc = Convert.ToUInt32((uint)(crc >> 8) ^ Crc32ReversedTable[(crc & 0xff) ^ bytes[i]]); } return crc; } } 参考资料

循环冗余检验 (CRC) 算法原理

CRC查找表法推导及代码实现比较

CRC(循环冗余校验)在线计算

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zypxpy.html