C語言實現CRC校驗算法的示例詳解
一、CRC介紹
CRC(Cyclic Redundancy Check,循環(huán)冗余校驗)是一種常用的錯誤檢測技術,用于驗證數據在傳輸或存儲過程中是否發(fā)生了錯誤。它通過對數據進行一系列計算和比較,生成一個校驗值,并將其附加到數據中。接收方可以使用相同的算法對接收到的數據進行校驗,然后與接收到的校驗值進行比較,從而確定數據是否存在錯誤。
CRC校驗通常用于以下方面:
(1)數據傳輸的可靠性:在數據通過媒體或網絡進行傳輸時,可能會發(fā)生噪聲、干擾或其他傳輸錯誤。通過在數據中添加CRC校驗值,接收方可以檢測到傳輸過程中是否發(fā)生了錯誤,并采取相應措施,如請求重新發(fā)送數據。
(2)存儲介質的完整性檢測:在存儲介質上讀取或寫入數據時,可能會發(fā)生位翻轉、介質故障等錯誤。通過在數據存儲時使用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位字節(jié)和無符號16位整數的數據類型進行計算的。
三、案例:數據校驗
場景:在單片機通信里,單片機需要向上位機發(fā)送一段數據。比如,存放在char buff[1024];這個數組里。 需要封裝兩個函數,單片機端調用函數對這段數據進行CRC校驗,封裝校驗值,然后上位機收到數據之后驗證CRC,校驗數據是否傳輸正確。
3.1 發(fā)送方(封裝校驗值)
#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);
? ?// 輸出發(fā)送的數據(包括CRC校驗值)
? ?printf("發(fā)送的數據:");
? ?for (int i = 0; i < length + 2; i++)
? {
? ? ? ?printf("%02X ", buff[i]);
? }
? ?printf("\n");
? ?return 0;
}在發(fā)送方的代碼中,使用 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校驗值是否正確。如果校驗通過,可以執(zhí)行進一步的數據處理操作;如果校驗失敗,可以進行異常處理。
示例中的CRC校驗函數是基于無符號8位字節(jié)和無符號16位整數的數據類型進行計算的??梢愿鶕嶋H需求進行適當修改,以適應不同的數據類型和CRC算法。
到此這篇關于C語言實現CRC校驗算法的示例詳解的文章就介紹到這了,更多相關C語言CRC校驗算法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++11的future和promise、parkged_task使用
這篇文章主要介紹了C++11的future和promise、parkged_task使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04
MFC中動態(tài)創(chuàng)建控件以及事件響應實現方法
這篇文章主要介紹了MFC中動態(tài)創(chuàng)建控件以及事件響應實現方法,詳細講解了MFC中動態(tài)創(chuàng)建控件以及事件響應的概念與實現方法,具有一定的實用價值,需要的朋友可以參考下2014-10-10

