rtx*_*x13 -1 c integer-overflow modulo undefined-behavior
参考C11 草案,第 3.4.3 节和C11 草案,第 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;
}
Run Code Online (Sandbox Code Playgroud)
终端会话:
$ ./overflow 2000000000,2000000000
INT_MAX = 2147483647
2000000000 + 2000000000 = -294967296
Run Code Online (Sandbox Code Playgroud)
即使使用像 gcc 这样“熟悉”的编译器,在像 x86 这样的“熟悉”平台上,有符号整数溢出也可以做一些不同于“明显的”二进制补码环绕行为的事情。
一个有趣的(或可能是可怕的)例子如下(参见 Godbolt):
#include <stdio.h>
int main(void) {
for (int i = 0; i >= 0; i += 1000000000) {
printf("%d\n", i);
}
printf("done\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
天真地,你会期望这个输出
0
1000000000
2000000000
done
Run Code Online (Sandbox Code Playgroud)
和gcc -O0你在一起就对了。但随着gcc -O2你得到
0
1000000000
2000000000
-1294967296
-294967296
705032704
...
Run Code Online (Sandbox Code Playgroud)
无限期地继续。算术是二进制补码环绕,好吧,但是循环条件中的比较似乎出了点问题。
事实上,如果您查看汇编输出,您会看到 gcc 完全省略了比较,并使循环无条件无限。可以推断出,如果没有溢出,循环永远不会终止,并且由于有符号整数溢出是未定义的行为,因此在这种情况下循环也可以不终止。因此,最简单和“最有效”的合法代码根本不终止,因为这避免了“不必要的”比较和条件跳转。
根据您的观点,您可能认为这很酷或有悖常理。
(对于额外的信贷:看什么icc -O2不,并试图解释)