CRC校验 C语言代码实现

时间:2024-05-18 16:50:11

    参考1: https://blog.****.net/d_leo/article/details/73572373   

    参考2:https://wenku.baidu.com/view/856d4f584b35eefdc9d3333f.html?from_page=view&from_mod=download

    CRC即循环冗余校验码(Cyclic Redundancy Check):其特征是信息字段和校验字段的长度可以任意选定。在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码也叫(N,K)码。对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。多项式是R+1位,且多项式G(x)首位和最后一位都为1。根据K位信息码和G(x)可以生成R位信息的校验码。

    R位校验码的具体生成过程为:假设要发送的K位信息码用多项式C(X)表示,将C(x)左移R位(可表示成C(x)*2R),这样C(x)的右边就会空出R位,这就是校验码的位置。用 C(x)*2R再模2除 (注意,这里不是直接采用二进制除法,而是采用一种称之为“模2除法”)。以生成多项式G(x)得到的余数就是R位校验码。

      R+1位多项式:任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。

     模2除法与算术除法类似,但每一位除的结果不影响其它位,即不向上一位借位,所以实际上就是异或。在循环冗余校验码(CRC)的计算中有应用到模2除法。

例:

CRC校验 C语言代码实现

现假设选择的CRC生成多项式为G(X) = X4 + X3 + 1,要求出二进制序列10110011的CRC校验码。下面是具体的计算过程:
①将多项式转化为二进制序列,由G(X) = X4 + X3 + 1可知二进制一种有五位,第4位、第三位和第零位分别为1,则序列为11001
②多项式的位数位5,则在数据帧的后面加上5-1位0,数据帧变为101100110000,然后使用模2除法除以除数11001,得到余数。

CRC校验 C语言代码实现

③将计算出来的CRC校验码添加在原始帧的后面,真正的数据帧为101100110100,再把这个数据帧发送到接收端。
④接收端收到数据帧后,用上面选定的除数,用模2除法除去,验证余数是否为0,如果为0,则说明数据帧没有出错。
 

我么假设发送信息为16位生成多项式采用17位的G(x)0x11021,得到16位的CRC校验码。信息码+校验码共32位

发送端进行CRC校验合成代码如下: 

#include<stdio.h>
#define _CRT_SECIRE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE

int crc;
int crc_CCITT_Send(int data_crc)  
{
    int data = 0, ax = 0, bx = 0, cx = 0;
    int px = 0x11021; //CRC_CCITT的生成多项式
    data = data_crc;  //data_crc为信息内容


    data <<= 16;        //信息左移16位
    ax = data >> 15;  //将前17位存在ax中,准备与多项式px做异或操作
    data <<= 17;   //除了前17位后剩下的15位


    for (cx = 15; cx > 0; cx--)
    {        
        if (((ax >> 16) & 0x1) == 0x1)
        {
            ax = ax ^ px;
        }
        ax <<= 1;        
        bx = data >> 31;        
        ax = ax + bx;        
        data <<= 1;
    }

    if (((ax >> 16) & 0x1) == 0x1)  //最后一位的异或操作
    {
        ax = ax ^ px;        
    }

    crc = ax; //crc 为根据信息内容data_crc和CRC_CCITT的生成多项式px求出的CRC码。

    printf("\n\n原始信息:%x\n", data_crc);
    data_crc <<= 16;
    data_crc += crc;
    printf("多项式信息:%x\n", px);
    printf("生成CRC校验码:%x\n", crc);
    printf("最后生成信息:%x\n", data_crc);
    return data_crc;
    
}

int main()
{
    FILE *fp_data, *fp_code;
    int crcnum, ch;
    fp_code = fopen("./code.txt", "w"); //加密文档
    fp_data = fopen("./data.txt", "w"); //原始文档

    printf("*****************************************************\n");
    printf("请输入原始信息,输入-1退出:");
    while (1)
    {
        scanf("%x", &ch);
        if (ch == -1)
        {
            break;
        }
        crcnum = crc_CCITT_Send(ch); //求出经过CRC校验后加密信息

        fprintf(fp_code, "%x ", crcnum);
        fprintf(fp_data, "%x ", ch);
    }
    
    printf("*****************************************************\n");
    fclose(fp_code);
    fclose(fp_data);

    system("pause");

    return 0;
}

CRC校验 C语言代码实现

 

 

接收端代码如下:

#include<stdio.h>
#define _CRT_SECIRE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE


int crc_CCITT_Recv(int data_crc)
{
    int data = 0, ax = 0, bx = 0, cx = 0;
    int px = 0x11021; //CRC_CCITT的生成多项式
    data = data_crc;  //data_crc为信息内容


    data <<= 16;
    ax = data >> 15;
    data <<= 17;
    for (cx = 15; cx > 0; cx--)
    {        
        if (((ax >> 16) & 0x1) == 0x1)
        {
            ax = ax ^ px;
        }
        ax <<= 1;        
        bx = data >> 31;        
        ax = ax + bx;        
        data <<= 1;
    }

    if (((ax >> 16) & 0x1) == 0x1)
    {
        ax = ax ^ px;        
    }

    printf("\n\n原始信息:%x\n", data_crc);
    printf("多项式信息:%x\n", px);
    printf("最后模2除结果:%x\n", ax);
    return ax; //ax 加密信息data_crc模2除多项式px的余数
    
}

int main()
{
    FILE  *fp_code;
    unsigned int data_crc, crcResult, ch, nLen=0;
    unsigned int n = 16;
    fp_code = fopen("./code.txt", "r"); //加密文档
    fseek(fp_code, 0, SEEK_END); //文件指针移到文件尾
    nLen = ftell(fp_code); //得到当前指针位置, 即是文件的长度
    printf("文件长度为%d\n", nLen);
    if (nLen <= 0)
    {
        printf("文件错误!\n");
        exit(1);
    }
    fseek(fp_code, 0, SEEK_SET); //文件指针移到文件开头

    printf("*****************************************************\n");
    printf("读取加密文件信息:");

    while (fscanf(fp_code, "%x", &ch) != EOF)
    {
        
        printf("读出数据为:%x\n", ch);    
        data_crc = ch >> n;        
        crcResult = crc_CCITT_Recv(data_crc); 
        ch <<= n;
        ch >>= n;

        if ((ch ^crcResult) != 0)
        {
            printf("传输错误!\n");
            exit(2);
        }
        
    }
    
    printf("\n\n\n文件传输成功!\n");
    
    printf("*****************************************************\n");
    fclose(fp_code);
;

    system("pause");

    return 0;
}

CRC校验 C语言代码实现