CRC校验详解(附代码示例)

article/2025/9/27 14:37:55

目录

1.CRC校验原理

2.生成多项式

3.以CRC-16校验为例讲解编程实现

3.3.1 完全按照CRC原理实现校验

3.3.2 工程中常用CRC校验过程

3.3.3 改进的CRC校验过程

4.以CRC-8校验为例讲解查表法

5.以CRC-16校验为例讲解查表法

5.1.生成表格

5.2.查表法实现

6.代码链接


CRC校验即循环冗余校验(Cyclic Redundancy Check),是基于数据计算一组效验码,用于核对数据传输过程中是否被更改或传输错误。首先看两个概念,后续会用到。

  • 模2除法:也叫模2运算,就是结果除以2后取余数。模2除法每一位除的结果不影响其它位,即不向上一位借位,所以实际上就是异或。在CRC计算中有应用到模2除法。
  • 多项式与二进制:二进制可表示成多项式的形式,比如二进制1101表示为: x3+x2+x0;1011表示为:x3+x1+x0。

1.CRC校验原理

CRC校验本质上是选取一个合适的除数,要进行校验的数据是被除数,然后做模2除法,得到的余数就是CRC校验值。

下面用具体的例子做讲解:给定一组数据A:10110011(二进制),选取除数B:11001。

  1. 首先需要在被除数A后加4个比特位0(具体加几个0是根据除数B的位数决定的,比如这里B是5位,那么A后面加4个0;如果B选6位,则A后面加5个0,总之加的0的个数比除数B的个数少1位。后面还会提到怎么添加)。
  2. 进行模2除法运算。注意每次都是模2运算,即异或。
  3. 最后得到余数C就是CRC校验值。注意余数位数必须比除数少1位,如果不够前面加0补齐。运算如下图所示

                   

2.生成多项式

第1章讲解了CRC校验的基本原理,通常我们把选取的除数称之为“生成多项式”。事实上,生成多项式的选取是由一定标准的,如果选的不好,那么检出错误的概率就会低很多。好在这个问题已经被专家们研究了很长一段时间了,对于我们这些使用者来说,只要把现成的成果拿来用就行了。下表是一些标准的CRC生成多项式,可以直接使用。

标准CRC生成多项式
名称生成多项式简记式
CRC-4x4+x+10x03
CRC-8x8+x5+x4+10x31
CRC-8x8+x2+x1+1 0x07
CRC-8x8+x6+x4+x3+x2+x10x5E
CRC-12x12+x11+x3+x+10x080F
CRC-16x16+x15+x2+1 0x8005
CRC16-CCITTx16+x12+x5+10x1021
CRC-32x32+x26+x23+...+x2+x+10x04C11DB7

更多标准CRC生成式请参考https://en.wikipedia.org/wiki/Cyclic_redundancy_check

有一点要特别注意,文献中提到的生成多项式经常会说到多项式的位宽(Width,简记为W),这个位宽不是多项式对应的二进制数的位数,而是位数减1。比如CRC8中用到的位宽为8的生成多项式,其实对应得二进制数有九位:100110001。另外一点,多项式表示和二进制表示都很繁琐,交流起来不方便,因此,文献中多用16进制简写法来表示,因为生成多项式的最高位肯定为1,最高位的位置由位宽可知,故在简记式中,将最高的1统一去掉了,如CRC32的生成多项式简记为04C11DB7实际上表示的是104C11DB7。当然,这样简记除了方便外,在编程计算时也有它的用处。所以在第一章中提到的在被除数后增加0的位数就是位宽,计算出的CRC校验值长度也是位宽。

3.以CRC-16校验为例讲解编程实现

3.3.1 完全按照CRC原理实现校验

实际工程中多使用CRC-16校验,即选取生成多项式为0x8005。按照前面提到的CRC校验原理,编程实现步骤如下:(注意实际编程时并不用这种直接的方法,如不想看可直接跳到3.3.2

  1. 预置1个16位的变量为CRC,此值存放CRC校验值,赋初值为0;
  2. 将需要校验的字符串str后面添加16个0;
  3. 如果变量CRC最高位为1,变量CRC与0x8005异或,然后将变量CRC左移1位,最低位补入1比特新的数据(来自需要校验的字符串str);
  4. 如果变量CRC最高位为0,直接将变量CRC左移1位,最低位补入1比特新的数据(来自需要校验的字符串str);
  5. 重复2-3步,直到字符串str最后1位补入变量CRC中;
  6. 此时得到的余数就是CRC校验值。

这种直接的方法有一个弊端,那就是在字符串前面加0,并不影响校验值,这就不符合我们的预期了。比如,我们想校验的1字节1001 1100,现在在前面补1字节0,变成2字节0000 0000 1001 1100,结果两个得到的校验值是一样的。所以在实际应用中,CRC校验过程做了一些改变:增加了“余数初始值”、“结果异或值”、“输入数据反转”和“输出数据反转”四个概念。

3.3.2 工程中常用CRC校验过程

  • 余数初始值:即在计算开始前,先给变量CRC赋的初值。
  • 结果异或值:即在计算结束后,得到的变量CRC与这个值进行异或操作,就得到了最终的校验值。
  • 输入数据反转:即在计算开始前,将需要校验的数据反转,如数据位1011,反转后为1101。
  • 输出数据反转:即在计算结束后,与结果异或值异或之前,计算值反转,如计算结果为1011,反转后为1101。

实际应用中,生成多项式、余数初始值、结果异或值、输入数据反转和输出数据反转是有对应关系的,这些对应关系是大家都遵守的标准,如下表所示:

表3-1 常见CRC参数模型
CRC算法名称多项式公式宽度多项式(16进制)初始值(16进制)结果异或值(16进制)输入值反转输出值反转
CRC-4/ITUx4 + x + 14030000truetrue
CRC-5/EPCx4 + x3 + 15090900falsefalse
CRC-5/ITUx5 + x4 + x2 + 15150000truetrue
CRC-5/USBx5 + x2 + 15051F1Ftruetrue
CRC-6/ITUx6 + x + 16030000truetrue
CRC-7/MMCx7 + x3 + 17090000falsefalse
CRC-8x8 + x2 + x + 18070000falsefalse
CRC-8/ITUx8 + x2 + x + 18070055falsefalse
CRC-8/ROHCx8 + x2 + x + 1807FF00truetrue
CRC-8/MAXIMx8 + x5 + x4 + 18310000truetrue
CRC-16/IBMx16 + x15 + x2 + 116800500000000truetrue
CRC-16/MAXIMx16 + x15 + x2 + 11680050000FFFFtruetrue
CRC-16/USBx16 + x15 + x2 + 1168005FFFFFFFFtruetrue
CRC-16/MODBUSx16 + x15 + x2 + 1168005FFFF0000truetrue
CRC-16/CCITTx16 + x12 + x5 + 116102100000000truetrue
CRC-16/CCITT-FALSEx16 + x12 + x5 + 1161021FFFF0000falsefalse
CRC-16/x5x16 + x12 + x5 + 1161021FFFFFFFFtruetrue
CRC-16/XMODEMx16 + x12 + x5 + 116102100000000falsefalse
CRC-16/DNPx16 + x13 + x12 + x11 + x10 + x8 + x6 + x5 + x2 + 1163D650000FFFFtruetrue
CRC-32x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFFFFFFFFFFtruetrue
CRC-32/MPEG-2x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFF00000000falsefalse

接下来以CRC-16/IBM校验为例,讲解工程中使用的CRC校验编程实现。具体实现时,以字节为单位进行计算。

  1. 预置1个16位的变量CRC,存放校验值,首先根据表3-1赋初值0x0000;
  2. 将第1个字节按照表3-1看是否需要反转,若需要,则按反转,若不需要,直接进入第3步。这里需要反转;
  3. 把第1个字节按照步骤2处理后,与16位的变量CRC的高8位相异或,把结果放于变量CRC,低8位数据不变;
  4. 把变量CRC的内容左移1位(朝高位)用0填补最低位,并检查左移后的移出位;
  5. 如果移出位为0:重复第4步(再次左移一位);如果移出位为1,变量CRC与多项式8005(1000 0000 0000 0101)进行异或;
  6. 重复步骤4和5,直到左移8次,这样整个8位数据全部进行了处理;
  7. 重复步骤2到步骤6,进行通讯信息帧下一个字节的处理;
  8. 将该通讯信息帧所有字节按上述步骤计算完成后,将得到的16位变量CRC按照表3-1看是否需要反转,这里需要反转;
  9. 最后,与结果异或值异或,得到的变量CRC即为CRC校验值;

我在这里按照如上方法整理了一个通用代码,包含CRC-8,CRC-16和CRC-32。代码如下:

type.h

#ifndef __TYPE_H__
#define __TYPE_H__
#include <stdio.h>typedef unsigned char        u8;
typedef unsigned short       u16;
typedef unsigned int         u32;
typedef unsigned long long   u64;typedef unsigned char        BOOL;
#define FALSE                0
#define TRUE                 1#endif

crc.h文件

#ifndef __CRC_H__
#define __CRC_H__
#include "type.h"typedef struct
{u8 poly;//多项式u8 InitValue;//初始值u8 xor;//结果异或值BOOL InputReverse;BOOL OutputReverse;
}CRC_8;typedef struct
{u16 poly;//多项式u16 InitValue;//初始值u16 xor;//结果异或值BOOL InputReverse;BOOL OutputReverse;
}CRC_16;typedef struct
{u32 poly;//多项式u32 InitValue;//初始值u32 xor;//结果异或值BOOL InputReverse;BOOL OutputReverse;
}CRC_32;const CRC_8 crc_8;
const CRC_8 crc_8_ITU;
const CRC_8 crc_8_ROHC;
const CRC_8 crc_8_MAXIM;const CRC_16 crc_16_IBM;
const CRC_16 crc_16_MAXIM;
const CRC_16 crc_16_USB;
const CRC_16 crc_16_MODBUS;
const CRC_16 crc_16_CCITT;
const CRC_16 crc_16_CCITT_FALSE;
const CRC_16 crc_16_X5;
const CRC_16 crc_16_XMODEM;
const CRC_16 crc_16_DNP;const CRC_32 crc_32;
const CRC_32 crc_32_MPEG2;u8 crc8(u8 *addr, int num,CRC_8 type) ;
u16 crc16(u8 *addr, int num,CRC_16 type) ;
u32 crc32(u8 *addr, int num,CRC_32 type) ;#endif

crc.c文件

#include <stdio.h>
#include "type.h"
#include "CRC.h"const CRC_8 crc_8 = {0x07,0x00,0x00,FALSE,FALSE};
const CRC_8 crc_8_ITU = {0x07,0x00,0x55,FALSE,FALSE};
const CRC_8 crc_8_ROHC = {0x07,0xff,0x00,TRUE,TRUE};
const CRC_8 crc_8_MAXIM = {0x31,0x00,0x00,TRUE,TRUE};const CRC_16 crc_16_IBM = {0x8005,0x0000,0x0000,TRUE,TRUE};
const CRC_16 crc_16_MAXIM = {0x8005,0x0000,0xffff,TRUE,TRUE};
const CRC_16 crc_16_USB = {0x8005,0xffff,0xffff,TRUE,TRUE};
const CRC_16 crc_16_MODBUS = {0x8005,0xffff,0x0000,TRUE,TRUE};
const CRC_16 crc_16_CCITT = {0x1021,0x0000,0x0000,TRUE,TRUE};
const CRC_16 crc_16_CCITT_FALSE = {0x1021,0xffff,0x0000,FALSE,FALSE};
const CRC_16 crc_16_X5 = {0x1021,0xffff,0xffff,TRUE,TRUE};
const CRC_16 crc_16_XMODEM = {0x1021,0x0000,0x0000,FALSE,FALSE};
const CRC_16 crc_16_DNP = {0x3d65,0x0000,0xffff,TRUE,TRUE};const CRC_32 crc_32 = {0x04c11db7,0xffffffff,0xffffffff,TRUE,TRUE};
const CRC_32 crc_32_MPEG2 = {0x04c11db7,0xffffffff,0x00000000,FALSE,FALSE};/*****************************************************************************
*function name:reverse8
*function: 字节反转,如1100 0101 反转后为1010 0011
*input:1字节
*output:反转后字节
******************************************************************************/
u8 reverse8(u8 data)
{u8 i;u8 temp=0;for(i=0;i<8;i++)	//字节反转temp |= ((data>>i) & 0x01)<<(7-i);return temp;
}
/*****************************************************************************
*function name:reverse16
*function: 双字节反转,如1100 0101 1110 0101反转后为1010 0111 1010 0011
*input:双字节
*output:反转后双字节
******************************************************************************/
u16 reverse16(u16 data)
{u8 i;u16 temp=0;for(i=0;i<16;i++)		//反转temp |= ((data>>i) & 0x0001)<<(15-i);return temp;
}
/*****************************************************************************
*function name:reverse32
*function: 32bit字反转
*input:32bit字
*output:反转后32bit字
******************************************************************************/
u32 reverse32(u32 data)
{u8 i;u32 temp=0;for(i=0;i<32;i++)		//反转temp |= ((data>>i) & 0x01)<<(31-i);return temp;
}/*****************************************************************************
*function name:crc8
*function: CRC校验,校验值为8位
*input:addr-数据首地址;num-数据长度(字节);type-CRC8的算法类型
*output:8位校验值
******************************************************************************/
u8 crc8(u8 *addr, int num,CRC_8 type)  
{  u8 data;u8 crc = type.InitValue;                   //初始值int i;  for (; num > 0; num--)               {  data = *addr++;if(type.InputReverse == TRUE)data = reverse8(data);                 //字节反转crc = crc ^ data ;                     //与crc初始值异或 for (i = 0; i < 8; i++)                //循环8位 {  if (crc & 0x80)                    //左移移出的位为1,左移后与多项式异或crc = (crc << 1) ^ type.poly;    else                               //否则直接左移crc <<= 1;                  }}if(type.OutputReverse == TRUE)             //满足条件,反转crc = reverse8(crc);crc = crc^type.xor;                        //最后返与结果异或值异或return(crc);                               //返回最终校验值
}/*****************************************************************************
*function name:crc16
*function: CRC校验,校验值为16位
*input:addr-数据首地址;num-数据长度(字节);type-CRC16的算法类型
*output:16位校验值
******************************************************************************/
u16 crc16(u8 *addr, int num,CRC_16 type)  
{  u8 data;u16 crc = type.InitValue;					//初始值int i;  for (; num > 0; num--)               {  data = *addr++;if(type.InputReverse == TRUE)data = reverse8(data);				//字节反转crc = crc ^ (data<<8) ;					//与crc初始值高8位异或 for (i = 0; i < 8; i++)					//循环8位 {  if (crc & 0x8000)					//左移移出的位为1,左移后与多项式异或crc = (crc << 1) ^ type.poly;    else		                        //否则直接左移crc <<= 1;                  }}if(type.OutputReverse == TRUE)              //满足条件,反转crc = reverse16(crc);crc = crc^type.xor;	                        //最后返与结果异或值异或return(crc);                                //返回最终校验值
}
/*****************************************************************************
*function name:crc32
*function: CRC校验,校验值为32位
*input:addr-数据首地址;num-数据长度(字节);type-CRC32的算法类型
*output:32位校验值
******************************************************************************/
u32 crc32(u8 *addr, int num,CRC_32 type)  
{  u8 data;u32 crc = type.InitValue;					//初始值int i;  for (; num > 0; num--)               {  data = *addr++;if(type.InputReverse == TRUE)data = reverse8(data);				//字节反转crc = crc ^ (data<<24) ;				//与crc初始值高8位异或 for (i = 0; i < 8; i++)					//循环8位 {  if (crc & 0x80000000)				//左移移出的位为1,左移后与多项式异或crc = (crc << 1) ^ type.poly;    else                                //否则直接左移crc <<= 1;                  }}if(type.OutputReverse == TRUE)              //满足条件,反转crc = reverse32(crc);crc = crc^type.xor;	                        //最后返与结果异或值异或return(crc);                                //返回最终校验值
}

调用时,只需传入相应的参数即可。经验证全部正确。如有疑问请评论留言。

3.3.3 改进的CRC校验过程

3.3.2中的代码具有通用性,但是可以看到效率不高。以crc16函数为例,需要判断字节是否需要反转,结束时,也需要判断是否需要反转,这都会耗费时间,如果需要反转,那么反转函数要花费更多时间。如何能提高效率呢?实际中我们常用某一种具体的校验方法,所以可以写单独的代码而非通用的,这样就可以省去两次判断反转的时间。以crc16/MAXIM为例,开始和结束都需要反转,改进后可以省略,具体操作如下:

/*****************************************************************************
*function name:crc16_MAXIM
*function: CRC校验,校验值为16位
*input:addr-数据首地址;num-数据长度(字节)
*output:16位校验值
******************************************************************************/
u16 crc16_MAXIM(u8 *addr, int num)  
{  u8 data;u16 crc = 0x0000;//初始值int i;  for (; num > 0; num--)             {  crc = crc ^ (*addr++) ;     //低8位异或for (i = 0; i < 8; i++)             {  if (crc & 0x0001)       //由于前面和后面省去了反转,所以这里是右移,且异或的值为多项式的反转值crc = (crc >> 1) ^ 0xA001;//右移后与多项式反转后异或else                   //否则直接右移crc >>= 1;                    }                               }return(crc^0xffff);            //返回校验值 
}  

读者可对比通用代码中crc16函数和crc16_MAXIM函数的区别。

4.以CRC-8校验为例讲解查表法

查表法速度快,但是表要占一部分内存,这是以空间换时间。

为了便于理解查表法,首先看3.3.2中CRC.c中u8 crc8(u8 *addr, int num,CRC_8 type)函数。为了方便观察,我将此段函数单独放在下面:

/*****************************************************************************
*function name:crc8
*function: CRC校验,校验值为8位
*input:addr-数据首地址;num-数据长度(字节);type-CRC8的算法类型
*output:8位校验值
******************************************************************************/
u8 crc8(u8 *addr, int num,CRC_8 type)  
{  u8 data;u8 crc = type.InitValue;                   //初始值int i;  for (; num > 0; num--)               {  data = *addr++;if(type.InputReverse == TRUE)data = reverse8(data);                 //字节反转crc = crc ^ data ;                     //与crc初始值异或 for (i = 0; i < 8; i++)                //循环8位 {  if (crc & 0x80)                    //左移移出的位为1,左移后与多项式异或crc = (crc << 1) ^ type.poly;    else                               //否则直接左移crc <<= 1;                  }}if(type.OutputReverse == TRUE)             //满足条件,反转crc = reverse8(crc);crc = crc^type.xor;                        //最后返与结果异或值异或return(crc);                               //返回最终校验值
}

观察上面代码,仔细发现18-24行的for循环可以生成一个表。进入for循环的变量crc大小为1个字节,即变量crc的大小可以为0-255之间的任何一个值,并且也只能是0-255之间的一个值。因此,可以实现将0-255都经过这个for循环,生成对应的值,生成的值也是0-255,这些生成的值就是crc要查的表,而传入for循环的变量crc就是表的索引值

以下代码是生成8位crc表的代码(多项式为0x07,核心的代码为11-17行for循环):

void GenerateCrc8Table(u8 *crc8Table)  
{  u8 crc=0;u16 i,j;for(j = 0;j<256;j++){if(!(j%16))                        //16个数为1行printf("\r\n");crc = (u8)j;for (i = 0; i < 8; i++)             {  if (crc & 0x80)               //最高位为1crc = (crc << 1) ^ 0x07;  //左移后与多项式异或else                          //否则直接左移crc <<= 1;                    }crc8Table[j] = crc;//取低字节printf("%2x ",crc);		}printf("\r\n");
}

生成的表如下:

需要注意的是,查表法所用的表根据多项式的不同而不同,所以再用不同多项式时,一定要重新生成对应的表。所以多项式为0x07的u8 crc8函数用查表法可以改写为如下:

/*****************************************************************************
*function name:crc8withTable
*function: CRC校验,校验值为8位
*input:addr-数据首地址;len-数据长度(字节);crc8Table-CRC8表
*output:8位校验值
******************************************************************************/
u8 crc8withTable(u8 *addr, int len,u8 *crc8Table)  
{  u8 data;u8 crc = 00;                   //初始值int i;  for (; len > 0; len--)               {  data = *addr++;crc = crc ^ data ;                     //与crc初始值异或 crc = crc8Table[crc];                  //替换下面for循环
//        for (i = 0; i < 8; i++)                //循环8位 
//        {  
//            if (crc & 0x80)                    //左移移出的位为1,左移后与多项式异或
//                crc = (crc << 1) ^ 0x07;    
//            else                               //否则直接左移
//                crc <<= 1;                  
//        }}crc = crc^0x00;                            //最后返与结果异或值异或return(crc);                               //返回最终校验值
}

可以看到第16行代码替换了for循环,直接从表中取值,速度快了很多。实际在用时,需要将表写成数组放在代码前面,这样代码就可以查表了。

5.以CRC-16校验为例讲解查表法

crc16查表法和crc8查表法类似,也是首先是生成一个表,然后再用查表代替for循环。

5.1.生成表格

以3.3.3中的CRC16代码为例,首先生成一个表,此表每个元素都是2字节,一共256个元素。但是需要将这个表拆分成两个表,其中高字节放在crcLowTable,低字节放在crcHighTable(我也不理解为什么这样做,但是按照这样的方法确实能实现查表法)。生成表代码如下:

/*****************************************************************************
*function name:GenerateCrc16Table
*function: 生成crc16查表法用的表格
*input: crcHighTable,crcLowTable:256大小的数组,即生成的表格首地址 
*output:无
******************************************************************************/
void GenerateCrc16Table(u8 *crcHighTable,u8 *crcLowTable)  
{  u16 crc=0;u16 i,j;for(j = 0;j<256;j++){if(!(j%8))printf("\r\n");crc = j;for (i = 0; i < 8; i++)             {  if (crc & 0x0001)       //由于前面和后面省去了反转,所以这里是右移,且异或的值为多项式的反转值crc = (crc >> 1) ^ 0xA001;//右移后与多项式反转后异或else                   //否则直接右移crc >>= 1;                    }crcHighTable[j] = (u8)(crc&0xff);//取低字节crcLowTable[j] = (u8)((crc>>8)&0xff);//取高字节printf("%4x  ",crc);		}printf("\r\n");
}

生成表如下:

整体表

      

拆分后低字节 crcHighTable          拆分后高字节crcLowTable

5.2.查表法实现

有了表格后,就可以实现查表法了(为什么用15-17行代码我也不清楚,这里可能涉及到推倒,欢迎大神们在评论区指导),代码如下:

/*****************************************************************************
*function name:Crc16withTable
*function: 用查表法计算CRC
*input:  addr:字符串起始地址;len :字符串长度;table:用到的表格
*output:无
******************************************************************************/
u16 Crc16withTable(u8 *addr, int len,u8 *crcHighTable,u8 *crcLowTable)  
{  u8 crcHi = 0x00;u8 crcLo = 0x00;u8 index;u16 crc;for (;len>0;len--)             {  index = crcLo ^ *(addr++);//低8位异或,得到表格索引值crcLo = crcHi ^ crcHighTable[index];crcHi = crcLowTable[index];}crc = (u16)(crcHi<<8 | crcLo);return(crc^0xffff);//返回校验值
}

大家可以自行验证,将3.3.3代码和5.2代码计算结果作比较。结果是一样的。实际在用时,需要将表写成数组放在代码前面,这样代码就可以查表了。

6.代码链接

https://download.csdn.net/download/u013073067/13138335

编译环境:VS2010

语言:C

如有疑问,欢迎大家在评论区留言讨论。

参考文献:

[1]https://www.cnblogs.com/sinferwu/p/7904279.html

[2]https://en.wikipedia.org/wiki/Cyclic_redundancy_check

[3]https://www.cnblogs.com/94cool/p/3559585.html


http://chatgpt.dhexx.cn/article/meFB8tRG.shtml

相关文章

详述CRC校验码(附代码)

关注星标公众号&#xff0c;不错过精彩内容 来源 | 一口Linux CRC校验应用比较广泛&#xff0c;通常在通信领域用的比较多&#xff0c;即便是自定义通信协议&#xff0c;也可以添加CRC校验码&#xff0c;使其通信更加可靠。 今天就来进一步描述CRC校验码。 一、CRC概念 1. 什么…

【科普】CRC校验(一)什么是CRC校验?

目录 CRC&#xff08;循环冗余校验&#xff09; CRC 校验码的生成 CRC 的发送方与接收方 发送方 接收方 除法异或运算示意图 CRC&#xff08;循环冗余校验&#xff09; CRC&#xff08;Cyclic Redundancy Check&#xff09;循环冗余检验&#xff0c;是一种用于检测数字数…

CRC校验原理及其C语言实现

文章目录 目录前言CRC算法简介CRC参数模型CRC计算CRC校验CRC计算的C语言实现CRC计算工具总结参考资料 目录 前言CRC算法简介CRC计算CRC校验CRC计算的C语言实现CRC计算工具总结 前言 最近的工作中&#xff0c;要实现对通信数据的CRC计算&#xff0c;所以花了两天的时间好好研…

Oracle Toad 导数,麒峰

标签&#xff1a; 补丁下载 x86 ia64 操作系统 迅雷下载 oracle it (2011-05-26 10:28) 标签&#xff1a; 授予的权限 主键约束 对象 角色管理 数据字典 oracle it 系统权限&#xff1a; create table :create any table: drop table: create procedure: execute anycedure: cr…

最优捕捞

一、问题重述 为了保护人类赖以生存的自然环境&#xff0c;可再生资源&#xff08;如渔业、林业资源&#xff09;的开发必须适度。一种合理、简化的策略是&#xff0c;在实现可持续收获的前提下&#xff0c;追求最大产量或最佳效益。 假设这种鱼分4个年龄组&#xff1a;称1龄…

短期趋势自用经传捕捞季节 通达信指标公式副图 源码 贴图

指标公式描述 短期趋势自用经传捕捞季节 通达信指标公式副图 源码 贴图 图示: 指标源码&#xff1a; WY1001:(2*CLOSEHIGHLOW)/4; WY1002:EMA(WY1001,2); WY1003:EMA(WY1002,2); WY1004:EMA(WY1003,2); XYS0:(WY1004-REF(WY1004,1))/REF(WY1004,1)*100; STICKLINE(XYS0>0,X…

股票指标使用 - 捕捞季节

股票指标里面我觉得这个指标是最实用的了&#xff0c;XX软件里面流行起来的。作为IT男&#xff0c;任何带有逻辑运算的都会让我感兴趣。 接下来就用简单易懂的文字介绍下这个指标怎么看(百度上搜到的都说了那么深奥) 如图&#xff1a; 优势&#xff1a;相对MACD指标来说&…

捕捞季节 通达信副图指标公式 源码

捕捞季节是一个趋势型指标&#xff0c;主要用于&#xff08;超&#xff09;短线的股价运行趋势状态监控。捕捞季节通达信指标公式主要用途是用来做短期买卖点操作的指标公式&#xff0c;适合那些做短期买卖的股民。 【指标用法】 紫色线上穿黄色线为金叉买入信号&#xff0c;…

通达信指标:捕捞季节

通达信【捕捞季节】指标 WY1001:(2CLOSEHIGHLOW)/3; WY1002:EMA(WY1001,3); WY1003:EMA(WY1002,3); WY1004:EMA(WY1003,3); XYS0:(WY1004-REF(WY1004,1))/REF(WY1004,1)100; STICKLINE(XYS0>0,XYS0,0,2,0),COLORRED; STICKLINE(XYS0<0,XYS0,0,2,0),COLORGREEN; PJGJ:AMO…

x86服务器与arm服务器

服务器是提供计算服务的设备&#xff0c;服务器的构成包括处理器、硬盘、内存、系统总线等&#xff0c;和通用的计算机架构类似&#xff0c;但是由于需要提供高可靠的服务&#xff0c;因此在处理能力、稳定性、可靠性、安全性、可扩展性、可管理性等方面要求较高。在网络环境下…

服务器 raid配置

这里写目录标题 首先启动Server在启动界面&#xff0c;按键盘ESC或Del键进入BIOS。设置启动模式为“LEGACY”传统模式&#xff0c;F4 保存并退出重启服务器。ctrlA进入raid配置 首先启动Server在启动界面&#xff0c;按键盘ESC或Del键进入BIOS。 设置启动模式为“LEGACY”传统模…

TaiShan服务器介绍

TaiShan服务器系列介绍 TaiShan 100服务器2016年 基于Kunpeng916处理器 最多16各DDR4内存 支持5个PCIe 3.0扩展插槽 支持SAS/SATA硬盘和SSD 支持板载GE/10GE网络 TaiShan 200服务器2019年 基于Kunpeng 920处理器 最多支持32个DDR4内存 支持最多8个PCLe 4.0扩展插槽 支持NVMe …

中国服务器销售排名,IDC Q3:华为FusionServer Pro智能服务器发货量、销售额荣登中国区x86标准服务器排名双冠王...

据IDC发布的《中国区服务器季度跟踪报告》显示&#xff0c;2020年第三季度中国区x86标准服务器市场(标注1)&#xff0c;华为FusionServer pro智能服务器发货量及销售额双居中国区第一(标注2)&#xff0c;其中机架、高密型号服务器&#xff0c;均列单品类发货量、销售额第一&…

华为x86服务器年销售额,卖了荣耀后,华为又要卖资产?这次是国内第2的X86服务器...

去年11月份&#xff0c;华为将荣耀卖了&#xff0c;从那以后荣耀独立了&#xff0c;开始了自由发展。 为何要卖荣耀&#xff0c;其实大家都知道的&#xff0c;华为把荣耀拿在手中&#xff0c;只能是等死&#xff0c;因为没有足够的芯片供应&#xff0c;荣耀无法推出新手机&…

x86服务器部署kylin v10(arm版)虚拟机

本次讲解在x86 linux环境下使用qemu进行arm版银河麒麟的部署&#xff0c;适用于运维人员进行相关项目的趟雷操作 qemu、VMware、docker区别 讲到虚拟机&#xff0c;得益于windows环境下的盛行&#xff0c;很多人第一时间想到的是VMware。亦或者考虑到部署的方便&#xff0c;考…

中国 X86 服务器市场 10 年来首次负增长

IDC《2019年第一季度中国X86服务器市场跟踪报告》显示&#xff0c;2019年第一季度中国X86服务器市场出货量662,504台&#xff0c;同比下滑0.7%&#xff1b;市场规模35.90亿美元&#xff08;约合240.90亿元人民币&#xff09;&#xff0c;同比增长13.5%。 2018年第一季度中国X86…

浪潮x86服务器芯片,用别人的芯片,做自己的X86服务器:国内浪潮第一,华为第二...

众所周知&#xff0c;在PC领域&#xff0c; X86 架构的芯片是一家独大的&#xff0c;虽然目前也有一些厂商想要向X86架构发起挑战&#xff0c;比如华为去年推出了鲲鹏主板&#xff0c;想将 鲲鹏920 用于PC&#xff0c;但就目前来讲&#xff0c;还需要很长时间。 所以一直以来&a…

2020年x86服务器厂商TOP10最新榜单,精彩不?

【全球财经观察 | 阿明微评】x86服务器市场的变化&#xff0c;阿明一直在关注&#xff0c;因为云计算的根基之一就是服务器。 x86服务器厂商这些年的发展也很有意思&#xff0c;首先看资本运作带来的影响。 在服务器整体市场领域&#xff0c;不管是因为资本组合形成新竞争力&…

x86 服务器常见问题和故障诊断流程

服务器常见问题汇总 服务器支撑着整个企业的信息数据&#xff0c;对公司的信息储存、业务开展、正常运作等等环节都具有着至关重要的意义。然而&#xff0c;服务器在日常运行过程中&#xff0c;由于其复杂的硬件结构、繁琐的运行原理&#xff0c;经常会出现一些大大小小的问题…

x86服务器(HP/DELL/IBM)测试分析(上)

x86架构是开放的&#xff0c;所以在同一个世界里的供应商做出的服务器都没有原则性差异&#xff0c;比如HP/DELL/IBM&#xff08;卖给联想了&#xff0c;工艺和设计仍然是这队的&#xff09;&#xff0c;比如联想&#xff08;收的IBM不算这里&#xff09;/浪潮。这些服务器都是…