C/C++实现crc码计算和校验

C/C++实现CRC码计算和校验

简介

CRC(Cyclic Redundancy Check)循环冗余校验码是一种通过计算来检测数据传输错误的方法,它通过对数据进行简单的计算得到一个固定长度的校验码,根据接收方收到的数据计算出的校验码和发送方计算出来的校验码进行比较来判断数据传输是否正确。

本文将介绍如何实现C/C++版的CRC码计算和校验,同时提供两个示例来说明如何使用。

CRC算法

对于一个要传输的数据d,CRC算法会计算出一个固定大小的校验码C,加上数据d和校验码C之后拼接成新的数据D,发送。接收方收到数据D之后,会计算接收到的数据的校验码C',如果C'与发送方计算出的校验码C一致,就说明数据传输正确无误。

通常我们使用的CRC算法都是基于多项式的下面这个公式计算得到的:

CRC(x) = r(x) mod g(x)

其中,x表示位,r(x)是要计算的数据,g(x)是一个系数多项式,mod是一个取模运算。

对于一个数据r(x)和一个G(x)多项式,执行CRC计算的过程如下:

  1. 将r(x)的高位填充G(x)的系数位数个0,得到p(x)
  2. 对p(x)和G(x)进行异或操作,得到余数d(x),把d(x)存储到p(x)的最高位
  3. 把p(x)的高位弹出,转到第二步,直到所有r(x)的位数处理完毕

最终得到的p(x)就是计算出的CRC码。接收方收到数据之后也用同样的算法计算出接收到的数据的CRC码,如果接收方计算出的CRC码与发送方计算出的CRC码相同,则说明数据传输正确。

C/C++实现

在C/C++中,我们可以通过计算得到一个数据的CRC码,也可以在接收到数据后计算数据的CRC码并校验。

CRC码计算

在C/C++中,计算CRC码的过程可以用一个函数来实现。我们可以定义一个函数,它接收一个指向数据的指针和数据的长度,同时再定义一个G(x)系数多项式,函数会返回计算出的CRC码。

一个常用的CRC16算法如下:

uint16_t CRC16(uint8_t *pdata, uint32_t len, uint16_t polynominal) {
    uint16_t crc = 0xFFFF;
    uint8_t i;
    while (len--) {
        crc ^= *pdata++;
        for (i = 0; i < 8; i++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= polynominal;
            }
            else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

该函数接收三个参数,pdata表示数据的指针,len表示数据长度,polynominal表示多项式系数。函数首先初始化一个crc变量为0xFFFF,然后对于每一个数据位执行一次循环,对于每一位,执行一次异或运算,然后进行8次迭代,每一次迭代都判断是否需要执行异或操作,最终得到的crc值就是计算出的CRC码。

CRC码校验

在C/C++中,校验CRC码的过程也可以用一个函数来实现。与计算CRC码的过程类似,校验CRC码的函数需要接收一个指向数据的指针和数据的长度以及一个该数据对应的CRC码。

一个常用的CRC16校验函数如下:

bool CheckCRC16(uint8_t *pdata, uint32_t len, uint16_t crc, uint16_t polynominal) {
    uint16_t crc_calculated = CRC16(pdata, len, polynominal);
    return crc == crc_calculated;
}

该函数接收四个参数,pdata表示数据的指针,len表示数据长度,crc表示接收到的CRC码,polynominal表示多项式系数。函数首先调用计算CRC码的函数计算出接收到的数据的CRC码,然后判断计算出的CRC码是否与接收到的CRC码相等,如果相等则返回true,否则返回false。

示例

下面我们提供两个示例来说明怎样使用C/C++来实现CRC码计算和校验。

示例一:计算字符串CRC码

#include <stdio.h>
#include <stdint.h>

/*CRC16多项式*/
const uint16_t POLYNOMIAL = 0xA001;

/*计算CRC16*/
uint16_t CRC16(uint8_t *pdata, uint32_t len, uint16_t polynominal) {
    uint16_t crc = 0xFFFF;
    uint8_t i;
    while (len--) {
        crc ^= *pdata++;
        for (i = 0; i < 8; i++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= polynominal;
            }
            else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

int main() {
    uint8_t data[] = {"Hello World!"};
    uint32_t len = sizeof(data);
    uint16_t crc_calculated = CRC16(data, len - 1, POLYNOMIAL);
    printf("CRC16: %04X\n", crc_calculated);
    return 0;
}

该示例演示了如何计算字符串的CRC16码。在主函数中,我们定义了一个字符串变量data,该字符串包含13个字符,分别为“Hello World!”,我们将该字符串作为数据,调用CRC16函数计算它的CRC16码,最终输出计算出的CRC16码。

示例二:校验接收到的数据

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

/*CRC16多项式*/
const uint16_t POLYNOMIAL = 0xA001;

bool CheckCRC16(uint8_t *pdata, uint32_t len, uint16_t crc, uint16_t polynominal) {
    uint16_t crc_calculated = CRC16(pdata, len, polynominal);
    return crc == crc_calculated;
}

int main() {
    uint8_t data[] = {"Hello World!"};
    uint32_t len = sizeof(data);
    /*模拟接收到的数据(包含CRC码)*/
    uint8_t received_data[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x94, 0x62 };
    /*从数据中提取CRC码*/
    uint16_t crc = received_data[len - 2] << 8 | received_data[len - 1];

    /*校验CRC码*/
    bool result = CheckCRC16(data, len - 1, crc, POLYNOMIAL);
    if (result) {
        printf("CRC Check passed.\n");
    }
    else {
        printf("CRC Check failed.\n");
    }
    return 0;
}

该示例演示了如何校验接收到的数据的CRC码。在主函数中,我们定义了一个字符串变量data,该字符串包含13个字符,分别为“Hello World!”,我们将该字符串作为数据,然后模拟接收到了一组数据,其中包含了我们发送的数据以及计算出的CRC码。我们从接收到的数据中提取出CRC码,然后调用CheckCRC16函数校验接收到的数据的CRC码是否正确,最终输出校验结果。

结论

本文介绍了如何在C/C++中实现CRC码计算和校验,通过两个示例演示了如何计算字符串的CRC码以及如何校验接收到的数据的CRC码。希望能帮助到需要进行CRC码计算和校验的读者。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C/C++实现crc码计算和校验 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言中的内联函数(inline)与宏定义(#define)详细解析

    C语言中的内联函数(inline)与宏定义(#define)详细解析 什么是内联函数 内联函数是C语言中的一种函数定义方式,它的定义和普通的函数定义方式不同,它以inline关键字开始,并与函数名之间不包含参数列表的括号。内联函数通常用于需要频繁调用、耗时短且代码比较简单的函数,例如加减乘除等算数运算。 内联函数的特点是函数调用时不需要进行栈帧的创建和销毁,…

    C 2023年5月23日
    00
  • C/C++高精度运算(大整数运算)详细讲解

    C/C++高精度运算(大整数运算)详细讲解 简介 在进行高精度运算时,我们需要使用到很大的整数进行计算,如:1000的阶乘,1到1000的和等。而C/C++默认的整型数据类型一般只能存储到2^32-1或2^64-1这样的范围,需要我们使用数组或链表等结构来存储这类大数。本篇文章将详细介绍如何使用C/C++实现大整数和高精度运算。 实现方式 在C/C++中,大…

    C 2023年5月22日
    00
  • 如何修复Win11上的ntdll.dll崩溃错误? ntdll.dll崩溃问题解决办法

    如果你遇到了Win11上的ntdll.dll崩溃错误,可以根据以下步骤进行修复: 1. 重新启动电脑 首先,尝试重新启动电脑,因为某些系统问题可以通过重新启动来解决。如果重新启动后,错误仍然存在,请继续下一步操作。 2. 更新系统和驱动程序 从开始菜单中打开设置,并点击“更新和安全”选项。在右侧窗口中,点击“Windows 更新”并查找可用更新。如果有更新,…

    C 2023年5月23日
    00
  • Notepad++ 运行 C 代码(MinGW-m64)

    Notepad++ 是一个常用的文本编辑器,它支持很多编程语言,包括 C 语言,同时它也很方便与其他工具配合使用。本攻略将介绍如何在 Notepad++ 中使用 MinGW-m64 工具集来编译并运行 C 代码,具体步骤如下: 步骤一:安装 MinGW-m64 工具集 MinGW(Minimalist GNU for Windows)是一个使用 GNU 工具…

    C 2023年5月22日
    00
  • Microsoft Visual C++ 程序的部署方法

    部署是将应用程序发布到用户机器上的过程,Microsoft Visual C++ 程序也需要进行部署才能在用户机器上运行。下面是 Microsoft Visual C++ 程序的部署方法的完整攻略: 1. 编译程序 在对程序进行部署之前,需要先确定最终版本的程序已经被编译成功。可以使用 Visual Studio 开发环境编译程序并生成可执行文件,或者使用命…

    C 2023年5月23日
    00
  • ubuntu 下编译C++代码出现的问题解决

    针对Ubuntu下编译C++代码出现的问题进行解决需要考虑以下几个步骤: 1.更新apt-get,确保系统软件包是最新的 sudo apt-get update sudo apt-get upgrade 2.安装C++编译器和构建工具 sudo apt-get install build-essential sudo apt-get install g++ …

    C 2023年5月23日
    00
  • Go语言设置JSON的默认值操作

    设置JSON的默认值是指当JSON中不存在某个键或该键对应的值为空时,使用预设的默认值来填充这个键对应的值。在Go语言中,可以使用“omitempty”选项或者自定义UnmarshalJSON函数来实现设置JSON的默认值操作。 下面是实现设置JSON默认值的两种方法及其示例说明: 方法一:使用“omitempty”选项 在结构体中,在JSON标记中添加“o…

    C 2023年5月23日
    00
  • C语言中随机数rand()函数详解

    下面是关于C语言中随机数rand()函数的详解攻略: C语言中随机数rand()函数详解 简介 rand()函数是C语言标准库中的一个伪随机数生成函数,头文件为stdlib.h。它的作用是生成一个在0到RAND_MAX之间的随机整数,其中RAND_MAX是一个常量,其值至少为32767。要生成不同的随机数序列,可以先调用srand()函数设置不同的seed种…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部