Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
893 views
in Technique[技术] by (71.8m points)

c - Bit shifting in internet checksums

This is almost certainly a very silly question, but for some reason I'm having trouble with internet checksum calculations. All of the algorithms basically look something like this:

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;}

I'm clear on everything except for the line:

sum += (sum >> 16);

It looks like the line immediately before it adds the top 16 bits to the bottom 16 bits, leaving all zeroes in the top 16 bits. If that's the case, then wouldn't sum >> 16 now be equal to zero? And if so, why is that line there?

Or am I (likely) just having a complete mental failure today?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is part of the definition of a one's complement sum. You take any overflow bits and add them back to the lower 16 bits. Adding them back could cause further overflow, so you repeat this until the upper bits end up all zero. So, conceptually it's this:

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

However this loop will only ever execute at most twice, so an explicit loop is not necessary. After the first addition there may or may not be an overflow with a carry bit ending up in the upper 16 bits. In that case the upper 16 bits will be 0x0001 and you will have to do one more addition to add that carry bit back in.

Imagine the worst case where sum ends up as 0xffffffff after the initial while loop. Then the additions will proceed as follows:

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

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

And there with two additions we are finished as the upper 16 bits are now clear. This is the worst case, so the loop can thus be unrolled to two additions.

(And then after all that you take the one's complement of the final sum, leading to the highly confusing name for this: the one's complement of the one's complement sum. It took me a long time to wrap my head around this the first time I implemented it—in particular that a one's complement sum does not involve the ~ complement operator.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...