【问题标题】:Bit shifting in internet checksums互联网校验和的位移
【发布时间】:2009-10-20 22:03:53
【问题描述】:

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

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 位中留下全零。如果是这种情况,那么 sum >> 16 现在不会等于零吗?如果是这样,那为什么会有那条线?

或者我(很可能)今天只是完全精神失常?

【问题讨论】:

    标签: c bit-manipulation checksum


    【解决方案1】:

    这是一个补码定义的一部分。您获取任何溢出位并将它们添加回低 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 位已经清晰了。这是最坏的情况,因此循环可以展开为两个加法。

    (并且 then 毕竟你取了最后一个和的补码,这导致了这个非常混乱的名字:一个补码的一个补码。我花了很长时间在我第一次实现它的时候把我的脑袋绕起来——特别是一个补码和不涉及~ 补码运算符。)

    【讨论】:

      【解决方案2】:

      你几乎是对的。

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

      例如,FFFF + FFFF => 1FFFE,或者FFFF + 1 => 10000

      【讨论】:

        【解决方案3】:

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

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

        将前 12 位和后 12 位相加。然后下一行对前 16 位的结果求和;由于进位操作,其中可能有一个。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-04-28
          • 2014-08-31
          • 2011-05-06
          • 2011-11-20
          • 2015-06-29
          • 2023-02-11
          • 2014-10-20
          • 1970-01-01
          相关资源
          最近更新 更多