我正在阅读有关检测 C 中溢出的技术。另外,显示检测溢出的错误解决方案的示例之一是:
/* Determine whether arguments can be added without overflow */
int tadd_ok(int x, int y) {
int sum = x+y;
return (sum-x == y) && (sum-y == x);
}
它说它不起作用,因为:
two’s-complement addition forms an abelian group, and so the expression (x+y)-x will evaluate to y regardless of whether or not the addition overflows, and that (x+y)-y will always evaluate to x
这到底是什么意思?这是否意味着C编译器替换sum
与 x+y
?
为了弄清楚它在说什么,我什至追踪了程序的汇编代码,但没有替换的迹象。
更新:我的问题的本质是,GCC 是否会评估表达式而不计算它?
这不是关于补码的问题。
您可以在here中看到示例输出。 .
最佳答案
如果您举一个 4 (0b0100) + 5 (0b0101)
的简单示例,您会发现无符号总和应为 9 (1001)
,实际上是 -7
以二进制补码表示。如果您随后使用补码算术将该总和 (0b1001) 减去 4:
0b1001 - 0b0100 = 0b1001 + 2s_complement(0b0100) = 0b1001 + 0b1100 = 0b1_0101
最终得到 0101,即 5(在 2 的补码运算期间删除溢出的最高有效位 1)。总和减去 5 等于 4:
0b1001 - 0b0101 = 0b1001 + 2s_complement(0b0101) = 0b1001 + 0b1011 = 0b1_0100
这满足您提供的 C 代码,但仍然导致溢出。
摘自维基百科关于 two's complement 的文章:
Two's complement Decimal 0111 7 0110 6 0101 5 0100 4 0011 3 0010 2 0001 1 0000 0 1111 −1 1110 −2 1101 −3 1100 −4 1011 −5 1010 −6 1001 −7 1000 −8
Update:
To demonstrate your INT_MAX example using my trivial 4 bit integer system with INT_MAX = 7 we can see the same result as your c code.
7 + 7 (0b0111 + 0b0111) = 0b1110 (-2 in two's complement)
就像上面的例子一样,相减,sum - 7
将等于 7
。
0b1110 - 0b0111 = 0b1110 + 2s_complement(0b0111) = 0b1110 + 0b1001 = 0b1_0111
关于c - Gcc 中的大数加法结果(阿贝尔群),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11476410/