互联网校验和中的位移

时间:2009-10-20 22:03:54

标签: c bit-manipulation checksum

这几乎肯定是一个非常愚蠢的问题,但由于某种原因,我在网络校验和计算方面遇到了麻烦。所有算法基本上都是这样的:

WORD chksm(WORD *startpos, WORD checklen){
ulong sum = 0;
WORD answer = 0;

while (checklen > 1)
{
    sum += *startpos++;
    checklen -= 2;
}

if (checklen == 1)
{
    *(BYTE *)(&answer) = *(BYTE *)startpos;
    sum += answer;
}

sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;

return answer;}

我清楚除了这条线以外的一切:

sum += (sum >> 16);

它看起来像是在它将前16位加到后16位之前的行,将所有零都保留在前16位中。如果是这种情况,那么就不会总结>> 16现在等于零?如果是这样,为什么那条线呢?

或者我(可能)今天只是完全精神衰竭?

3 个答案:

答案 0 :(得分:4)

这是一个补码和的定义的一部分。您获取任何溢出位并将它们添加回低16位。将它们添加回来可能会导致进一步溢出,所以重复此操作直到高位结束为零。所以,概念上就是这样:

while (sum >> 16 != 0) {
    sum = (sum >> 16) + (sum & 0xffff);
}

然而,这个循环最多只能执行两次,所以不需要显式循环。在第一次加法之后,可能有或没有溢出,进位位在高16位中结束。在这种情况下,高16位将为0x0001,您将不得不再做一次添加以将该进位添加回来。

想象一下最坏的情况,在初始while循环之后sum总和为0xffffffff。然后添加将如下进行:

sum = (0xffffffff >> 16) + (0xffffffff & 0xffff)
    = 0xffff + 0xffff
    = 0x1fffe

sum = (0x1fffe >> 16) + (0x1fffe & 0xffff)
    = 0x1 + 0xfffe
    = 0xffff

我们完成了两个新增功能,因为高16位现在已经清除了。这是最糟糕的情况,因此循环可以展开为两个添加。

(而然后毕竟你拿了最后一笔的一个补码,导致这个名字非常混乱:一个补码的补码。我花了很长时间在我第一次实现它的时候绕过这个 - 特别是一个补码和不涉及~补码运算符。)

答案 1 :(得分:3)

你几乎是对的。

由于进位,高16位可能为1。

例如,FFFF + FFFF => 1FFFEFFFF + 1 => 10000

答案 2 :(得分:1)

我认为ulong是32位宽,这意味着:

sum = (sum >> 16) + (sum & 0xffff)
sum += (sum >> 16);

将顶部的sicteen位和底部sisteen位加在一起。然后下一行将前十六位的结果相加;由于进位操作可能会有一个。