CRC32 例程與理解

原理

原理我就不詳細(xì)介紹了暖释,維基百科什么的有很多平项,大概意思就是這么一套操作過后可以極大概率地檢測出數(shù)據(jù)錯誤。我又怎么會告訴你們我也沒有完全看懂。

實現(xiàn)

直接計算法

/**
 * CRC32 校驗函數(shù)
 * @param pdata 數(shù)據(jù)指針
 * @param len 數(shù)據(jù)長度
 * @param crc 初值或上段數(shù)據(jù)校驗結(jié)果
 * @param poly 多項式
 */
uint32_t CRC32(const uint8_t* pdata, int len, uint32_t crc, uint32_t poly)
{
    for (int i = 0; i < len; i++, pdata++)
    {
        crc ^= ((uint32_t)*pdata << 24);

        for (int bits = 0; bits < 8; bits++)
        {
            if (crc & 0x80000000)
            {
                crc = (crc << 1) ^ poly;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    return crc;
}

稍微解釋一下代碼镣煮,大概步驟是:

  1. 把新的數(shù)據(jù) xor 到之前數(shù)據(jù)的最高 byte
  2. 判斷最高 bit,如果是 0 就左移鄙麦,是 1 就左移后 xor poly
  3. 處理完最高 8 個 bits 結(jié)束

網(wǎng)上有些例程是右移處理典唇,其實本質(zhì)是一樣的,只要生成 CRC 的程序和校驗它的程序是一致的就可以胯府。

為了證明我不是隨便找了一段沒驗證過的代碼就貼出來介衔,我這里給出一個 CRC Online Calculator,我貼出的代碼能夠得出和它一致的結(jié)果骂因,各位自己調(diào)試代碼的時候也可以有個參考炎咖。

使用的時候有幾點注意:

  • 選擇 CRC-32
  • 由于我給出的代碼沒有進行位翻轉(zhuǎn)操作,所以選擇 Custom,然后兩個 reflected 的鉤去掉
  • Final Xor Value 填 0
  • 剩下的你應(yīng)該懂的

雖然這段代碼簡單明白乘盼,但是網(wǎng)上類似的東西也不少升熊,發(fā)個貼子沒點干貨似乎不太好意思。那么我就多給點料绸栅。

查表法

了解多一些的朋友會知道级野,雖然直接計算的方法代碼特別簡單,但是循環(huán)次數(shù)太多效率不夠高阴幌。根據(jù) xor 運算的結(jié)合律特性勺阐,可以使用查表法提高運行效率卷中。

static uint32_t gsTable[256];

void CRC32_TableInit(uint32_t poly)
{
    for(uint32_t i = 0; i < 256; i++)
    {
        uint32_t crc = i << 24;

        for (int bits = 0; bits < 8; bits++)
        {
            if (crc & 0x80000000)
            {
                crc = (crc << 1) ^ poly;
            }
            else
            {
                crc <<= 1;
            }
        }

        gsTable[i] = crc;
    }
}

uint32_t CRC32_Table(const uint8_t* pdata, int len, uint32_t crc)
{
    uint8_t index;

    for (int i = 0; i < len; i++, pdata++)
    {
        index = *pdata ^ (crc >> 24);
        crc = (crc << 8) ^ gsTable[index];
    }
    return crc;
}

對比上面的代碼矛双,其實就是把 8 bits 的循環(huán)抽了出來。從直接計算的代碼我們看出蟆豫,這八次循環(huán)的計算效果议忽,其實完全取決于新數(shù)據(jù) xor 之后 crc 最高 byte 的值。那么我們?nèi)绻堰@一個 byte 所有可能的值對應(yīng)的計算結(jié)果先存起來十减,就得到了一個 256 數(shù)據(jù)的表栈幸。

使用的時候就拿 xor 之后的最高 byte 去查表,然后把 crc 直接左移 8 個 bits帮辟,再進行一次 xor 就妥了速址。

有些朋友會疑惑,這樣一番操作是不是真的能得到同樣的結(jié)果由驹。我們可以觀察一下表的值芍锚,發(fā)現(xiàn)它的第 0 個值必然是 0,而第 1 個值蔓榄,必然等于 poly并炮。為什么呢?因為如果最高 byte 是 0 的話甥郑,數(shù)據(jù)除了會左移 8 個 bits 以外逃魄,剩下的 bits 都不會改變(xor 0 值也不變)。而最高 byte 如果是 1 的話澜搅,那么它會在第 8 次左移之后 xor 一次 poly伍俘。可以看出至少在這兩種情況的時候勉躺,兩段代碼的計算效果是等價的养篓,而后面的更多種情況就只能自己體會一下了。

查表法是挺不錯赂蕴,但是網(wǎng)上其實也能找得到柳弄。所以呢,就再上一份干貨,這是我實際踩過的坑碧注。

STM32 CRC32

下面的代碼嚣伐,與 STM32 中自帶的 CRC32 模塊的計算效果是等效的。

#define CRC_STM32_POLY          0x04c11db7
#define CRC_STM32_INIT_VALUE    0xFFFFFFFF

uint32_t STM32_CRC32(const uint32_t* pdata, int len, uint32_t crc, uint32_t poly)
{
    for (int i = 0; i < len; i++, pdata++)
    {
        crc ^= *pdata;

        for (int bits = 0; bits < 32; bits++)
        {
            if ((crc & 0x80000000) != 0)
            {
                crc = (crc << 1) ^ poly;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    return crc;
}

那么它和我們上面一般的 CRC 運算有什么不同呢萍丐?細(xì)心的朋友可能發(fā)現(xiàn)了轩端,它的計算是 32 bits 一輪的,而由于其是小端存儲逝变,所以其實是從第四個 byte 的最高 bit 開始計算的基茵。和從第一個 byte 開始計算的 CRC 結(jié)果是不一樣的,而且輸入數(shù)據(jù) bytes 個數(shù)必須補零到 4 的整數(shù)倍壳影。

如果你以為它和一開始介紹的算法一樣拱层,就會被它坑到 T^T。而它的算法是內(nèi)置的宴咧,沒得修改根灯,所以只要你想用,就必須按它的來掺栅。

好了烙肺,干貨上完,感謝閱讀氧卧。

Jalon 原創(chuàng)桃笙,轉(zhuǎn)載署名,商用聯(lián)系本人沙绝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搏明,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宿饱,更是在濱河造成了極大的恐慌熏瞄,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谬以,死亡現(xiàn)場離奇詭異强饮,居然都是意外死亡,警方通過查閱死者的電腦和手機为黎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門邮丰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铭乾,你說我怎么就攤上這事剪廉。” “怎么了炕檩?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵斗蒋,是天一觀的道長捌斧。 經(jīng)常有香客問我,道長泉沾,這世上最難降的妖魔是什么捞蚂? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮跷究,結(jié)果婚禮上姓迅,老公的妹妹穿的比我還像新娘。我一直安慰自己俊马,他們只是感情好丁存,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柴我,像睡著了一般解寝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屯换,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天编丘,我揣著相機與錄音与学,去河邊找鬼彤悔。 笑死,一個胖子當(dāng)著我的面吹牛索守,可吹牛的內(nèi)容都是我干的晕窑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼卵佛,長吁一口氣:“原來是場噩夢啊……” “哼杨赤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起截汪,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疾牲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后衙解,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阳柔,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年蚓峦,在試婚紗的時候發(fā)現(xiàn)自己被綠了舌剂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡暑椰,死狀恐怖霍转,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情一汽,我是刑警寧澤避消,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響岩喷,放射性物質(zhì)發(fā)生泄漏委造。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一均驶、第九天 我趴在偏房一處隱蔽的房頂上張望昏兆。 院中可真熱鬧,春花似錦妇穴、人聲如沸爬虱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跑筝。三九已至,卻和暖如春瞒滴,著一層夾襖步出監(jiān)牢的瞬間曲梗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工妓忍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留虏两,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓世剖,卻偏偏與公主長得像定罢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子旁瘫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容