我正在学习创建原始数据包并在this教程之后发送它。一切都有意义,直到我到达生成校验和的代码。
unsigned short csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
看起来他正在总结缓冲区中的所有单词。但是当我点击
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
我完全迷失了。看起来他把所有的位都移位了,基本上丢弃除了进位之外的所有位,然后将它加回到原始总和中?为什么& 0xfff必要吗?毕竟,为什么再次添加进位?是因为可能会有第二次执行?
答案 0 :(得分:4)
该行:
sum = (sum >> 16) + (sum & 0xffff);
在32位整数中添加左右16位字。它基本上将数字分成两半并将两半加在一起。 sum>> 16给你左半部分,sum& 0xffff给你右半部分。
然后当这些2加在一起时,它们可能会溢出。这一行:
sum += (sum >> 16);
将溢出添加回原始编号。
答案 1 :(得分:0)
计算的校验和是16位(unsigned short
通常是16位),但变量sum
是unsigned long
,因此可能是32位。
因此,操作sum >> 16
捕获总和的高位字,所有单词总和超过16位的时间都可以保持。然后将其与sum & 0xffff
混合,这只是总和中的低位字。
这样,总和的所有位都“折入”,以便它们对最终结果有贡献。