这是 lwIP 源代码中的一个宏:
#define TCP_SEQ_LT(a,b) ((int32_t)((uint32_t)(a) - (uint32_t)(b)) < 0)
它用于检查 TCP 序列号是否小于另一个,考虑到序列号何时回绕。它利用了算术环绕的事实,但我无法理解在这种特殊情况下它是如何工作的。
谁能解释发生了什么以及为什么上述工作?
这是 lwIP 源代码中的一个宏:
#define TCP_SEQ_LT(a,b) ((int32_t)((uint32_t)(a) - (uint32_t)(b)) < 0)
它用于检查 TCP 序列号是否小于另一个,考虑到序列号何时回绕。它利用了算术环绕的事实,但我无法理解在这种特殊情况下它是如何工作的。
谁能解释发生了什么以及为什么上述工作?
举一个简单的 4 位整数示例,其中 a = 5 和 b = 6。每个整数的二进制表示形式为
a = 0101
b = 0110
现在,当我们减去这些(或取 b 的补码,与 a 相加,然后加 1)时,我们得到以下结果
0101
1001
+ 1
-----
1111
1111 等于 15(无符号)或 -1(有符号,再次使用二进制补码翻译)。通过将这两个数字转换为无符号数,我们确保如果 b > a,则两者之间的差将是一个很大的无符号数,并且设置了它的最高位。当把这个大的无符号数转换成它的有符号数时,由于设置了 MSB,我们总是会得到一个负数。
正如 nos 所指出的,当序列号从最大无符号值回绕回最小值时,宏还将使用上述算术返回最大值 < min,因此它很有用。
在环绕时,a 将比 b 大得多。如果我们减去它们,结果也会非常大,即设置了它的高位。如果我们然后将结果视为有符号值,则较大的差异将变为负数,小于 0。
如果您有 2 个相隔 2G 的序列号,它将不起作用,但这不会发生。
因为它在与零比较之前首先被转换为有符号整数。请记住,从左到右读取的第一位确定有符号数的符号,但用于将 unsigned int 的范围增加一个额外的位。
示例:假设您有一个 4 位无符号数。这意味着 1001 是 17。但作为有符号整数,这将是 -1。
现在假设我们做了 b0010 - b0100。这以 b1110 结束。无符号是 14,有符号的是 -6。