轻松理解CRC差错检测算法(A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS)八

来源:互联网 发布:淘宝宝贝创建时间查询 编辑:程序博客网 时间:2024/05/09 01:59

10 一个有点不太完美的表驱动实现

<–作者版本见本系列第一篇
尽管下面的这句代码,精简,优雅
r=0; while (len–) r = ((r << 8) | *p++) ^ t[(r >> 24) & 0xFF];
这些追求最优化的骇客们还是不会轻易放过它。问题是,你可以看到,这个循环是作用于经过附加的信息,为了使用这段代码,你不得不附加w/8个0到信息的尾部,这应该在把p指向信息之前完成。取决于运行环境因素,这可能是,也可能不是一个问题。但是,如果数据块是由其他的语言的代码转交过来的,这就会有大麻烦。一个可行的办法是仅仅把以下的代码追加到上述循环后面,每次循环处理一个字节的0。
for (i=0; i<W/4; i++) r = (r << 8) ^ t[(r >> 24) & 0xFF];
这对我而言,看起来是个合理的方案。但是,出于减小在未来澄清的代价(你不得不承认,这已经是这段代码中已经很吓人的东西了),我可以进一步重新组织这个小循环,以便避免在信息后附加全0字节,或者如上所述在代码尾部显式处理全0字节。为了解释最优化,我们回到前面给出的处理流程图中。
table算法
现在,注意到以下的事实:
尾部:w/4个附加的出现在信息尾部的全0字节,会被和其他的字节一样,从右边加载到寄存器中,但是它们的值(0)无论如何不会对寄存器中的值造成影响。因为,1)与0异或不改变目标字节的值。2)4个字节从不会从寄存器的左边传播出去,一旦会传播出去,它们的0可能会有一些影响。这样,W/4个附加的全0字节的目的是去驱动另外W/4字节的循环,这样的话在真实数据的尾部会一路穿透寄存器。
头部:如果初始值为0,最开始的4个迭代,只会造成4个最开始字节从右侧移动。这是因为,开始的32们控制位是全0的,这样没有值会异或入寄存器中。即使初始值还是0,算法中开始的4字节迭代,将会只移动开始的4个字节异或入寄存器,然后,把它们与一些常数值进行异或(这是寄存器的初始值的一个功能)
有了这些事实,结合异或的特性。
(A xor B) xor C = A xor (B xor C)
表明信息的字节不需要真正穿透过了寄存器的W/4字节。相反,它们可以在它被使用来索引查找表前,被异或进入最高字节。这引起以下的算法版本修订。
直接表算法
注:这个算法的寄存器的初始值,必须是上一次算法运行时,经过4次移动后得到的值。注:表是如此的,如果 之前的算法使用的是0,新的算法也会这样。
这是一个相同的算法,会得到同样的结果。C代码看起来是这样的:
r=0; while (len--) r = (r<<8) ^ t[(r >> 24) ^ *p++];
这就是你很可能在眼下的表驱动CRC实现中看到的代码。出于潜在的考虑,一些FF掩码必须逻辑求和,但是基本上,上面的循环是这样的。我称这个是直接表算法。

在试着理解这些东西时,我推导出了SIMPLE算法,和基于SIMPLE算法推演出的表驱动算法。但是,当我把我自己的代码和真实实现的代码相比,我有点抓狂,为什么字节是在寄存器错误的一端进行异或运算。我花了好些时间才弄明白他们的算法和我的算法本质上是一样的。这也是我写这个文章的部分原因,尽管除法和我早一些的表驱动实现显然没有什么关系,这样的联系在当开始从“错误”的一端取出数据时,被清除掉了。这看起来是错的。你已经走了这么远,你不仅明白了理论,实践,优化实践,而且你也明白了你将会钻研于其中的真实的代码。还有更复杂的吗?是的,还有。

0 0