对常量和变量进行除法运算有什么区别

What is the difference between performing division operation on constants and variables

根据此link,执行INT_MIN / -1 除法运算将导致程序在i386 CPU 中终止。我的处理器是32位架构的,我用的是GCC编译器。我做了以下实验来检查它。

int a = INT_MIN;
int b = -1;
int c = a / b;
printf("%d\n",c);

根据上面提到的 link 中指定的信息,该程序终止并抛出浮点异常。但是当我换一种方式尝试时,情况就不一样了。


int c = INT_MIN / -1;
printf("%d\n",c);  

编译器在编译该程序后抛出以下警告。

iso.c: In function ‘main’:
iso.c:6:18: warning: integer overflow in expression [-Woverflow]
int c = INT_MIN / -1;
_____________^

但是我得到了输出-2147483648。我又多做了两个实验


int a = INT_MIN;
int b = -1;
printf("%d\n",a / b);

这是一个浮点异常。


printf("%d\n",INT_MIN / -1);

这引发了以下编译器警告。

iso.c: In function ‘main’:
iso.c:6:24: warning: integer overflow in expression [-Woverflow]
printf("%d\n",INT_MIN / -1);
__________________^

这个程序的输出又是-2147483648。


经过所有这些实验,我注意到直接对常量进行除法运算的结果与对变量进行除法运算的结果不同。那么究竟是什么造成了这种差异?

根据标准,这两个结果都是可以接受的。 C99 的 n1256 草案说(强调我的):

6.5 Expressions
...
5 If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

在 2 的补码整数表示中,INT_MIN/-1INT_MAX + 1 因此该操作调用未定义的行为,因此任何结果(包括崩溃)都是可接受的

正如@tilz0R 在他的评论中所解释的那样,当值在变量中传递时,该操作在 运行 时间执行并引发 SIGFPE 信号。但是当操作只涉及编译时常量时,操作由编译器在编译时执行。在 gcc 实现中,编译器保护自己免受错误的影响,并简单地使用其对 INT_MAX + 1 的最佳表示。在 32 位 2 的补码实现中,INT_MAX 是 0x7fffffff,因此 INT_MAX + 1 是(在有符号溢出后)0x80000000 或再次 INT_MIN (-2147483648)