解读一段循环冗余校验(CRC)算法程序

今天遇到一段这样的程序,一时半会很难读懂:

alt_u32 crc32_bit(alt_u8 *ptr, alt_u32 len, alt_u32 gx)
{
    alt_u8 i;
    alt_u32 crc = 0xffffffff;
    while (len--)
    {
        for (i = 1; i != 0; i <<= 1)
        {
            if ((crc & 0x80000000) != 0)
            {
                crc <<= 1;
                crc ^= gx;
            }
            else
                crc <<= 1;
            if ((*ptr & i) != 0)
                crc ^= gx;
        }
        ptr++;
    }
    return (Reflect(crc, 32) ^ 0xffffffff);
}

这是一个计算循环冗余校验码的算法,CRC的作用是通过校验对数据的正确性进行检查。这个程序的写法让人费解,下面一句句进行思考解读。
已知传进的指针ptr指向一个数据数组,len为其长度,gx为校验多项式,是8位数据。
外层的循环是len次,每次len减一,ptr增一,因此每次ptr指向一个8位数据。
内层循环是8次,刚好对应数据的8位。

在循环内部:因为有两个条件语句,根据不同条件和结果列如下:
crc & 0x80000000 == 0,*ptr & i == 0 :crc<<=1
crc & 0x80000000 == 0,*ptr & i == 1 :crc<<=1;crc^=gx
crc & 0x80000000 == 1,*ptr & i == 0 :crc<<=1;crc^=gx
crc & 0x80000000 == 1,*ptr & i == 1 :crc<<=1
注意第四种情况中,crc先异或后又再次异或 等于没有做任何操作。

其中,crc & 0x80000000是判断crc的最高位(记作条件A),*ptr & i是判断第i位(记作条件B)。之后的操作是将crc左移(记作操作C),以及crc左移后与gx异或(记作操作D)。
从以上判断可以得出条件-结果对:
A==B-> C
A != B -> D
当两者相同时执行C操作,不相同时执行D操作。C、D操作唯一区别是是否与gx进行异或,因此可以将唯一不同的操作归纳:将操作C视为值0,D视为1。即是说:操作值等于A^B。也就是当数据第i位与crc最高位的相异时执行操作:crc^=gx。
解读到此处,已然明了。

crc变量在此处代表前一次计算的结果,初始为全1。将其最高位与数据最第i位相比,不同则将其进行与gx的异或。
第一次异或:0xffff与gx,将会得到~gx<<1(gx全反位左移)
第二次异或:~gx<< x+1 与 gx,x代表最近一次不满足A^B的条件的位数
……
在草稿纸上进行演算,发现这就是模二除法,最后得到的crc就是余数。但是要注意,这里的 i 是从数据的低位开始计算的,而crc是从高位起。也就是说,每一个数据都是反着算的(这与机器大小端无关),因此在最后需要将其位全部反过来(Reflect函数)才能用于校验。

其中的具体原理还没有弄清楚,但是解读的思路给了一些其他的启发。另外,这里查到了一篇CRC算法详解,其思路比较清晰:
http://blog.csdn.net/liyuanbhu/article/details/7882789

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值