C語言實現(xiàn)CRC校驗算法的示例詳解
一、CRC介紹
CRC(Cyclic Redundancy Check,循環(huán)冗余校驗)是一種常用的錯誤檢測技術,用于驗證數(shù)據(jù)在傳輸或存儲過程中是否發(fā)生了錯誤。它通過對數(shù)據(jù)進行一系列計算和比較,生成一個校驗值,并將其附加到數(shù)據(jù)中。接收方可以使用相同的算法對接收到的數(shù)據(jù)進行校驗,然后與接收到的校驗值進行比較,從而確定數(shù)據(jù)是否存在錯誤。
CRC校驗通常用于以下方面:
(1)數(shù)據(jù)傳輸?shù)目煽啃裕涸跀?shù)據(jù)通過媒體或網(wǎng)絡進行傳輸時,可能會發(fā)生噪聲、干擾或其他傳輸錯誤。通過在數(shù)據(jù)中添加CRC校驗值,接收方可以檢測到傳輸過程中是否發(fā)生了錯誤,并采取相應措施,如請求重新發(fā)送數(shù)據(jù)。
(2)存儲介質的完整性檢測:在存儲介質上讀取或寫入數(shù)據(jù)時,可能會發(fā)生位翻轉、介質故障等錯誤。通過在數(shù)據(jù)存儲時使用CRC校驗,可以在讀取數(shù)據(jù)時檢測到這些錯誤,并提供數(shù)據(jù)的完整性保證。
(3)網(wǎng)絡通信協(xié)議:許多網(wǎng)絡通信協(xié)議(如Ethernet、WiFi、USB等)使用CRC校驗作為數(shù)據(jù)幀的一部分,以確保傳輸?shù)臄?shù)據(jù)準確無誤。接收方在接收到數(shù)據(jù)幀后,使用CRC校驗來驗證數(shù)據(jù)的完整性。
在項目中,CRC校驗廣泛應用于各種通信系統(tǒng)、存儲系統(tǒng)和數(shù)據(jù)傳輸系統(tǒng)中。通過使用CRC校驗,可以提高數(shù)據(jù)的可靠性,并減少傳輸或存儲過程中的錯誤。它可以檢測到數(shù)據(jù)位級別的錯誤,并提供一定程度的數(shù)據(jù)完整性保證。CRC校驗在保障數(shù)據(jù)可靠性和完整性方面具有重要作用,特別是在對數(shù)據(jù)完整性有較高要求的應用場景中。
二、示例代碼
以下C語言代碼演示如何獲取一段數(shù)據(jù)的CRC校驗值:
#include <stdio.h> #include <stdint.h> ? // CRC校驗函數(shù) 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校驗函數(shù)調用 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
函數(shù)實現(xiàn)了CRC校驗的計算邏輯。采用了常用的CRC-16算法(0xA001多項式)。calculateCRC
函數(shù)是對 crc16
的封裝,用于調用CRC校驗函數(shù)并返回校驗結果。
在 main
函數(shù)中,通過調用 calculateCRC
函數(shù)來計算給定數(shù)據(jù)的CRC校驗值,并將結果打印輸出。
代碼中的CRC校驗函數(shù)和封裝函數(shù)是基于無符號8位字節(jié)和無符號16位整數(shù)的數(shù)據(jù)類型進行計算的。
三、案例:數(shù)據(jù)校驗
場景:在單片機通信里,單片機需要向上位機發(fā)送一段數(shù)據(jù)。比如,存放在char buff[1024];這個數(shù)組里。 需要封裝兩個函數(shù),單片機端調用函數(shù)對這段數(shù)據(jù)進行CRC校驗,封裝校驗值,然后上位機收到數(shù)據(jù)之后驗證CRC,校驗數(shù)據(jù)是否傳輸正確。
3.1 發(fā)送方(封裝校驗值)
#include <stdio.h> #include <stdint.h> ? // CRC校驗函數(shù) 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校驗值到數(shù)據(jù)中 void appendCRC(uint8_t *data, int length) { ? ?uint16_t crc = crc16(data, length); ? ?data[length] = crc & 0xFF; // 將低8位放入數(shù)據(jù)末尾 ? ?data[length + 1] = crc >> 8; // 將高8位放入數(shù)據(jù)末尾的下一個位置 } ? int main() { ? ?uint8_t buff[1024] = {0x01, 0x02, 0x03, 0x04, 0x05}; // 原始數(shù)據(jù) ? ?int length = 5; // 數(shù)據(jù)長度 ? ?// 在原始數(shù)據(jù)后追加CRC校驗值 ? ?appendCRC(buff, length); ? ?// 輸出發(fā)送的數(shù)據(jù)(包括CRC校驗值) ? ?printf("發(fā)送的數(shù)據(jù):"); ? ?for (int i = 0; i < length + 2; i++) ? { ? ? ? ?printf("%02X ", buff[i]); ? } ? ?printf("\n"); ? ?return 0; }
在發(fā)送方的代碼中,使用 appendCRC
函數(shù)將CRC校驗值追加到原始數(shù)據(jù)的末尾。
3.2 接收方(校驗數(shù)據(jù))
#include <stdio.h> #include <stdint.h> ? // CRC校驗函數(shù) 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); // 去除數(shù)據(jù)末尾的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}; // 收到的數(shù)據(jù)(包括CRC校驗值) ? ?int length = sizeof(receivedData) / sizeof(receivedData[0]); ? ?// 驗證CRC校驗值是否正確 ? ?int crcResult = verifyCRC(receivedData, length); ? ?if (crcResult) ? { ? ? ? ?printf("CRC校驗通過\n"); ? ? ? ?// TODO: 進一步處理正確的數(shù)據(jù) ? } ? ?else ? { ? ? ? ?printf("CRC校驗失敗\n"); ? ? ? ?// TODO: 處理校驗失敗的情況 ? } ? ?return 0; }
在接收方的代碼中,使用 verifyCRC
函數(shù)驗證接收到的數(shù)據(jù)的CRC校驗值是否正確。如果校驗通過,可以執(zhí)行進一步的數(shù)據(jù)處理操作;如果校驗失敗,可以進行異常處理。
示例中的CRC校驗函數(shù)是基于無符號8位字節(jié)和無符號16位整數(shù)的數(shù)據(jù)類型進行計算的??梢愿鶕?jù)實際需求進行適當修改,以適應不同的數(shù)據(jù)類型和CRC算法。
到此這篇關于C語言實現(xiàn)CRC校驗算法的示例詳解的文章就介紹到這了,更多相關C語言CRC校驗算法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
stl容器set,map,vector之erase用法與返回值詳細解析
在使用 list、set 或 map遍歷刪除某些元素時可以這樣使用,如下所示2013-09-09