1. 程式人生 > >Boost學習之CRC校驗

Boost學習之CRC校驗

迴圈冗餘校驗(CRC)是一種根據網路資料封包或電腦檔案等資料產生簡短固定位數的一種雜湊函式,主要用來檢測或校驗資料傳輸或者儲存後可能出現的錯誤。它是由W. Wesley Peterson在他1961年發表的論文中披露。[來自維基百科]

CRC校驗的基本思想是利用線性編碼理論,在傳送端根據要傳送的k位二進位制碼序列,以一定的規則產生一個校驗用的監督碼(既CRC碼) r位,並附在資訊後邊,構成一個新的二進位制碼序列數共(k+r)位,最後傳送出去。在接收端, 則根據資訊碼和CRC碼之間所遵循的規則進行檢驗,以確定傳送中是否出錯。

假設要生成一個16位的CRC碼,它產生的規則是先將要傳送的二進位制序列數左移16位(既乘以216

)後,再除以一個多項式,最後所得到的餘數既是CRC碼。任意一個由二進位制位串組成的程式碼都可以和一個係數僅為‘0’ 和‘1’取值的多項式一一對應。例如:程式碼1010111對應的多項式為x6+x4+x2+x+1,而多項式 x5+x3+x2+x+1對應的程式碼101111。

Boost裡的CRC庫

Boost中的CRC庫定義於標頭檔案<boost/crc.hpp>中,主要提供了兩個CRC類:class crc_basicclass crc_optimal。crc_basic 是按位運算的,速度較慢。crc_optimal按位數取相應的位元組數作為單位運算,速度很快。

crc_basic和crc_optimal的用法相差不大,主要區別是CRC引數設定的位置不同,下面是它們的類宣告和建構函式

template < std::size_t Bits > class crc_basic;
explicit crc_basic( value_type truncated_polynominal,
 value_type initial_remainder = 0, value_type final_xor_value = 0,
 bool reflect_input = false, bool reflect_remainder = false );

template < std::size_t Bits, impl_def TruncPoly = 0u,
 impl_def InitRem = 0u
, impl_def FinalXor = 0u, bool ReflectIn = false, bool ReflectRem = false > class crc_optimal; explicit crc_optimal( value_type init_rem = InitRem );

對比crc_basic建構函式引數名和crc_optimal模板引數名,可以看出其實它們是一樣的。只是crc_basic在建構函式裡設定CRC引數,而crc_optimal是在模板引數裡。

下面先說說這幾個引數的意義:

BitsCRC校驗位數
truncated_polynominal/TruncPoly多項式,由於除數總是比餘數大一位,而作為除數的多項式最高位總是為1。在描述CRC多項式時,最高位被忽略,這樣可以讓多項式(除數)和CRC校驗和(餘數)使用同一資料型別來表示。
initial_remainder/InitRem初始值
final_xor_value/FinalXor最後的異或值,返回值是校驗和與之異或的值。
reflect_input/ReflectIn反轉輸入值
reflect_remainder/ReflectRem反轉輸出值

幾個常用方法

操作描述
void process_bit( bool bit );把一個位(bit)作為資料傳遞給 CRC 機,更新中間 CRC。只在crc_basic中定義。
void process_bits( unsigned char bits, std::size_t bit_count );對 bits 中最低的 bit_count 個位(從最重要的位算起)應用 process_bit。如果 bit_count 超過了每個位元組的位數,結果未定義。只在crc_basic中定義。
void process_byte( unsigned char byte );對 byte 中的所有位應用 process_bit。如果不需要反射,這些位以從最重要到最不重要的順序依次提供;否則以相反的順序提供。
void process_block( void const *bytes_begin, void const *bytes_end );對給定的從 bytes_begin 開始,到 bytes_end 結束的記憶體塊應用 process_byte。各個位元組依上述順序處理。
void process_bytes( void const *buffer, std::size_t byte_count );對給定的從 buffer 開始的長度為 byte_count 位元組的記憶體塊應用 process_byte。各個位元組依升序處理。
value_type checksum() const;返回到目前為止所有傳遞過去的資料的 CRC 檢驗和,這個值可能經過了餘數反射和異或運算。
void operator ()( unsigned char byte );呼叫 process_byte。有了這個方法,就可以把 CRC 機物件當作一個(有狀態的)函式物件來使用。只在快速 CRC 機中定義。
value_type operator ()() const;呼叫 checksum。有了這個這個方法,就可以把 CRC 機物件當作一個發生器(generator)函式物件來使用。只在快速 CRC 機中定義。

示例程式碼

#include <boost/crc.hpp> // for boost::crc_basic, boost::crc_optimal
#include <boost/cstdint.hpp> // for boost::uint16_t

#include <algorithm> // for std::for_each
#include <cassert> // for assert
#include <cstddef> // for std::size_t
#include <iostream> // for std::cout
#include <ostream> // for std::endl

// Main function
int main ()
{
 // This is "123456789" in ASCII

 unsigned char const data[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
 0x38, 0x39 };
 std::size_t const data_len = sizeof( data ) / sizeof( data[0] );

 // The expected CRC for the given data

 boost::uint16_t const expected = 0x29B1;

 // Simulate CRC-CCITT

 boost::crc_basic<16> crc_ccitt1( 0x1021, 0xFFFF, 0, false, false );
 crc_ccitt1.process_bytes( data, data_len );
 assert( crc_ccitt1.checksum() == expected );

 // Repeat with the optimal version (assuming a 16-bit type exists)

 boost::crc_optimal<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt2;
 crc_ccitt2 = std::for_each( data, data + data_len, crc_ccitt2 );
 assert( crc_ccitt2() == expected );

 std::cout << "All tests passed." << std::endl;
 return 0;
}

另外,Boost的CRC庫已經定義了幾個常用的CRC引數組合:

typedef crc_optimal<16, 0x8005, 0, 0, true, true> crc_16_type;
typedef crc_optimal<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt_type;
typedef crc_optimal<16, 0x8408, 0, 0, true, true> crc_xmodem_type;
typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true>
 crc_32_type;

附常用生成多項式

下面是常用 CRC(按照 ITU-IEEE 規範)[來自維基百科]

名稱多項式表示法:正常或者翻轉
CRC-1x + 1
(用途:硬體,也稱為奇偶校驗位)
0x1 or 0x1 (0x1)
CRC-5-CCITTx5 + x3 + x + 1 (ITU G.704 標準)0x15 (0x??)
CRC-5-USBx5 + x2 + 1 (用途:USB 信令包)0x05 or 0x14 (0x9)
CRC-7x7 + x3 + 1 (用途:通訊系統)0x09 or 0x48 (0x11)
CRC-8-ATMx8 + x2 + x + 1 (用途:ATM HEC)0x07 or 0xE0 (0xC1)
CRC-8-CCITTx8 + x7 + x3 + x2 + 1 (用途:1-Wire 匯流排)
CRC-8-Dallas/Maximx8 + x5 + x4 + 1 (用途:1-Wire bus)0x31 or 0x8C
CRC-8x8 + x7 + x6 + x4 + x2 + 10xEA(0x??)
CRC-10x10 + x9 + x5 + x4 + x + 10x233 (0x????)
CRC-12x12 + x11 + x3 + x2 + x + 1
(用途:通訊系統)
0x80F or 0xF01 (0xE03)
CRC-16-Fletcher參見 Fletcher's checksum用於 Adler-32 A & B CRC
CRC-16-CCITTx16 + x12 + x5 + 1 (X25V.41Bluetooth, PPP, IrDA)0x1021 or 0x8408 (0x0811)
CRC-16-IBMx16 +x15 + x2 + 10x8005 or 0xA001 (0x4003)
CRC-16-BBSx16 + x15 + x10 + x3 (用途:XMODEM 協議)0x8408 (0x????)
CRC-32-AdlerSee Adler-32參見 Adler-32
CRC-32-MPEG2See IEEE 802.3參見 IEEE 802.3
CRC-32-IEEE 802.3x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 +x4 + x2 + x + 10x04C11DB7 or 0xEDB88320 (0xDB710641)
CRC-32C (Castagnoli)x32 + x28 + x27 + x26 + x25 + x23 + x22 + x20 + x19 + x18 + x14 + x13 + x11 + x10 + x9 + x8 + x6 + 10x1EDC6F41 or 0x82F63B78 (0x05EC76F1)
CRC-64-ISOx64 + x4 + x3 + x + 1
(use: ISO 3309)
0x000000000000001B or 0xD800000000000000 (0xB000000000000001)
CRC-64-ECMA-182x64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 + x35 + x33 + x32
x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 +x12 + x10 + x9 + x7 + x4 + x + 1
(as described in ECMA-182 p.63)
0x42F0E1EBA9EA3693 or 0xC96C5795D7870F42 (0x92D8AF2BAF0E1E85)
CRC-128IEEE-ITU 標準。被 MD5 & SHA-1 取代
CRC-160IEEE-ITU 標準。被 MD5 & SHA-1 取代