C语言实现CRC校验算法的示例详解

 更新时间:2023年08月09日 16:26:08   作者:DS小龙哥  
CRC(Cyclic Redundancy Check,循环冗余校验)是一种常用的错误检测技术,用于验证数据在传输或存储过程中是否发生了错误,本文主要介绍了C语言如何实现CRC校验算法,需要的可以参考一下

一、CRC介绍

CRC(Cyclic Redundancy Check,循环冗余校验)是一种常用的错误检测技术,用于验证数据在传输或存储过程中是否发生了错误。它通过对数据进行一系列计算和比较,生成一个校验值,并将其附加到数据中。接收方可以使用相同的算法对接收到的数据进行校验,然后与接收到的校验值进行比较,从而确定数据是否存在错误。

CRC校验通常用于以下方面:

(1)数据传输的可靠性:在数据通过媒体或网络进行传输时,可能会发生噪声、干扰或其他传输错误。通过在数据中添加CRC校验值,接收方可以检测到传输过程中是否发生了错误,并采取相应措施,如请求重新发送数据。

(2)存储介质的完整性检测:在存储介质上读取或写入数据时,可能会发生位翻转、介质故障等错误。通过在数据存储时使用CRC校验,可以在读取数据时检测到这些错误,并提供数据的完整性保证。

(3)网络通信协议:许多网络通信协议(如Ethernet、WiFi、USB等)使用CRC校验作为数据帧的一部分,以确保传输的数据准确无误。接收方在接收到数据帧后,使用CRC校验来验证数据的完整性。

在项目中,CRC校验广泛应用于各种通信系统、存储系统和数据传输系统中。通过使用CRC校验,可以提高数据的可靠性,并减少传输或存储过程中的错误。它可以检测到数据位级别的错误,并提供一定程度的数据完整性保证。CRC校验在保障数据可靠性和完整性方面具有重要作用,特别是在对数据完整性有较高要求的应用场景中。

二、示例代码

以下C语言代码演示如何获取一段数据的CRC校验值:

#include <stdio.h>
#include <stdint.h>
​
// CRC校验函数
uint16_t crc16(uint8_t *data, int length)
{
    uint16_t crc = 0xFFFF;
    for (int i = 0; i < length; i++)
    {
        crc ^= data[i];
        for (int j = 0; j < 8; j++)
        {
            if (crc & 1)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    return crc;
}
​
// 封装的CRC校验函数调用
uint16_t calculateCRC(uint8_t *data, int length)
{
    return crc16(data, length);
}
​
int main()
{
    uint8_t message[] = {0x01, 0x02, 0x03, 0x04, 0x05};
    int length = sizeof(message) / sizeof(message[0]);
    uint16_t crc = calculateCRC(message, length);
    printf("CRC: 0x%04X\n", crc);
    return 0;
}

在上面代码中,crc16 函数实现了CRC校验的计算逻辑。采用了常用的CRC-16算法(0xA001多项式)。calculateCRC 函数是对 crc16 的封装,用于调用CRC校验函数并返回校验结果。

main 函数中,通过调用 calculateCRC 函数来计算给定数据的CRC校验值,并将结果打印输出。

代码中的CRC校验函数和封装函数是基于无符号8位字节和无符号16位整数的数据类型进行计算的。

三、案例:数据校验

场景:在单片机通信里,单片机需要向上位机发送一段数据。比如,存放在char buff[1024];这个数组里。 需要封装两个函数,单片机端调用函数对这段数据进行CRC校验,封装校验值,然后上位机收到数据之后验证CRC,校验数据是否传输正确。

3.1 发送方(封装校验值)

#include <stdio.h>
#include <stdint.h>
​
// CRC校验函数
uint16_t crc16(uint8_t *data, int length)
{
    uint16_t crc = 0xFFFF;
    for (int i = 0; i < length; i++)
    {
        crc ^= data[i];
        for (int j = 0; j < 8; j++)
        {
            if (crc & 1)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    return crc;
}
​
// 封装CRC校验值到数据中
void appendCRC(uint8_t *data, int length)
{
    uint16_t crc = crc16(data, length);
    data[length] = crc & 0xFF; // 将低8位放入数据末尾
    data[length + 1] = crc >> 8; // 将高8位放入数据末尾的下一个位置
}
​
int main()
{
    uint8_t buff[1024] = {0x01, 0x02, 0x03, 0x04, 0x05}; // 原始数据
    int length = 5; // 数据长度
    // 在原始数据后追加CRC校验值
    appendCRC(buff, length);
    // 输出发送的数据(包括CRC校验值)
    printf("发送的数据:");
    for (int i = 0; i < length + 2; i++)
    {
        printf("%02X ", buff[i]);
    }
    printf("\n");
    return 0;
}

在发送方的代码中,使用 appendCRC 函数将CRC校验值追加到原始数据的末尾。

3.2 接收方(校验数据)

#include <stdio.h>
#include <stdint.h>
​
// CRC校验函数
uint16_t crc16(uint8_t *data, int length)
{
    uint16_t crc = 0xFFFF;
    for (int i = 0; i < length; i++)
    {
        crc ^= data[i];
        for (int j = 0; j < 8; j++)
        {
            if (crc & 1)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    return crc;
}
​
// 验证CRC校验值是否正确
int verifyCRC(uint8_t *data, int length)
{
    uint16_t crc = crc16(data, length - 2); // 去除数据末尾的CRC校验值
    // 获取接收到的CRC校验值
    uint16_t receivedCRC = (data[length - 1] << 8) | data[length - 2];
    // 比较计算得到的CRC校验值与接收到的CRC校验值
    if (crc == receivedCRC)
    {
        return 1; // 校验通过
    }
    else
    {
        return 0; // 校验失败
    }
}
​
int main()
{
    uint8_t receivedData[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0xC2, 0x45}; // 收到的数据(包括CRC校验值)
    int length = sizeof(receivedData) / sizeof(receivedData[0]);
    // 验证CRC校验值是否正确
    int crcResult = verifyCRC(receivedData, length);
    if (crcResult)
    {
        printf("CRC校验通过\n");
        // TODO: 进一步处理正确的数据
    }
    else
    {
        printf("CRC校验失败\n");
        // TODO: 处理校验失败的情况
    }
    return 0;
}

在接收方的代码中,使用 verifyCRC 函数验证接收到的数据的CRC校验值是否正确。如果校验通过,可以执行进一步的数据处理操作;如果校验失败,可以进行异常处理。

示例中的CRC校验函数是基于无符号8位字节和无符号16位整数的数据类型进行计算的。可以根据实际需求进行适当修改,以适应不同的数据类型和CRC算法。

到此这篇关于C语言实现CRC校验算法的示例详解的文章就介绍到这了,更多相关C语言CRC校验算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中std::transform的使用小结

    C++中std::transform的使用小结

    std::transform 是 C++ 标准库中的一个算法,本文主要介绍了C++中std::transform的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • 浅谈const变量赋值报错分析

    浅谈const变量赋值报错分析

    在类中 只有静态变量能赋值 如果你不赋值 编译器会认为你这个变量根本没用 不能被修改 又没有初始值 两个办法 在构造函数的初始化列表赋值 或者在const前面加一个static
    2015-07-07
  • C/C++ 判断计算机存储器字节序(端序)的几种方式

    C/C++ 判断计算机存储器字节序(端序)的几种方式

    字节序是计算机存储数据的格式,主存储器(主存)的字节序对程序的移植性和兼容性至关重要,利用联合体、指针、位移和掩码等方法可以检测和处理字节序问题,对于内存数据操作重要,也关系到跨平台和网络通信的数据处理
    2024-10-10
  • C/C++ Qt QThread线程组件的具体使用

    C/C++ Qt QThread线程组件的具体使用

    QThread库是QT中提供的跨平台多线程实现方案,本文详细的介绍了Qt QThread线程组件的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • 使用c++编程实现简单的打字小游戏

    使用c++编程实现简单的打字小游戏

    这篇文章主要为大家介绍了使用c++编程语言来实现一个非常简单的打字小游戏过程实现的示例代码,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-10-10
  • 基于C语言实现推箱子游戏

    基于C语言实现推箱子游戏

    这篇文章主要为大家详细介绍了基于C语言实现推箱子游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C++ 如何用cout输出hex,oct,dec的解决方法

    C++ 如何用cout输出hex,oct,dec的解决方法

    本篇文章是对C++中如何用cout输出hex,oct,dec的方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 一文详解C++ 智能指针的原理、分类及使用

    一文详解C++ 智能指针的原理、分类及使用

    智能指针的本质就是使用一个对象来接管一段开辟的空间,这篇文章就来给大家介绍介绍C++智能指针的原理,分类及使用方法,文中有详细的代码示例,需要的朋友可以参考下
    2023-05-05
  • C++中对象的赋值与复制操作详细解析

    C++中对象的赋值与复制操作详细解析

    对象之间的赋值也是通过赋值运算符“=”进行的。本来赋值运算符“=”只能用来对单个的变量赋值,现在被扩展为两个同类对象之间的赋值,这是通过对赋值运算符的重载实现的
    2013-10-10
  • C语言怎样用指针指向字符串

    C语言怎样用指针指向字符串

    这篇文章主要介绍了C语言怎样用指针指向字符串问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10

最新评论