哪些“C”实现不实现有符号整数的模运算?

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)

Nat*_*dge 5

即使使用像 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,并试图解释)