参考C11 draft, section 3.4.3和C11 draft, section H.2.2,我正在寻找实现除带符号整数的模运算以外的行为的“ C”实现。
特别是,我正在寻找默认行为的实例,这可能是由于底层计算机体系结构所致。
这是一个代码示例和终端会话,它说明有符号整数的模算术行为:
overflow.c
:
#include <stdio.h>
#include <limits.h>
int main(int argc, char *argv[])
{
int a, b;
printf ( "INT_MAX = %d\n", INT_MAX );
if ( argc == 2 && sscanf(argv[1], "%d,%d", &a, &b) == 2 ) {
int c = a + b;
printf ( "%d + %d = %d\n", a, b, c );
}
return 0;
}
终端会议:
$ ./overflow 2000000000,2000000000
INT_MAX = 2147483647
2000000000 + 2000000000 = -294967296
即使使用像gcc这样的“熟悉的”编译器,在x86这样的“熟悉的”平台上,有符号整数溢出也可以执行“显而易见的”二进制补码环绕行为以外的其他操作。
以下是一个有趣(或可能令人恐惧)的例子(see on godbolt:]
#include <stdio.h>
int main(void) {
for (int i = 0; i >= 0; i += 1000000000) {
printf("%d\n", i);
}
printf("done\n");
return 0;
}
天真,您希望它输出
0
1000000000
2000000000
done
并且使用gcc -O0
,您将是对的。但是使用gcc -O2
,您会得到
0
1000000000
2000000000
-1294967296
-294967296
705032704
...
无限期继续。算术是二进制补码环绕,但是,循环条件中的比较似乎出了点问题。
实际上,如果您查看程序集输出,您会发现gcc完全省略了比较,并使循环无条件地变为无限。可以推断出,如果没有溢出,则循环永远不会终止,并且由于有符号整数溢出是未定义的行为,因此在这种情况下也可以使循环不终止。因此,最简单和“最有效”的法律代码永远不会终止,因为这避免了“不必要的”比较和有条件的跳转。
根据您的观点,您可能认为这很酷,也可能很反常。