【问题标题】:What is the difference between performing division operation on constants and variables对常量和变量进行除法运算有什么区别
【发布时间】:2017-11-27 02:19:59
【问题描述】:

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

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

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


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

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

iso.c:在函数'main'中:
iso.c:6:18:警告:表达式中的整数溢出 [-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:在函数'main'中:
iso.c:6:24:警告:表达式中的整数溢出 [-Woverflow]
printf("%d\n",INT_MIN / -1);
__________________^

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


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

【问题讨论】:

  • 编译器可能很聪明,并认识到这部分int a = INT_MIN; int b = -1; int c = a / b;可以由编译器完成,而不是由CPU完成,因此您在运行程序时已经有了结果,甚至没有执行除法。另一方面,如果除法前变量值未知(scanf为输入读取值),则肯定会进行除法指令。

标签: c variables gcc constants integer-division


【解决方案1】:

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

6.5 表达式
...
5 如果在计算表达式期间出现异常情况(即,如果 结果未在数学上定义或不在可表示的值范围内 type),行为未定义。

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

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

【讨论】:

    猜你喜欢
    • 2011-01-14
    • 2011-01-04
    • 2015-08-13
    • 2012-10-22
    • 2011-03-14
    • 2016-07-19
    • 2015-05-19
    • 1970-01-01
    相关资源
    最近更新 更多