我目前正在学习C程序但是我遇到了一些奇怪的行为 我期待一个结果,但是这样打印了两个结果
$ ./a.out
yes1 0x80000000
yes3 0x80000000
怎么可能呢?
我无法理解结果。
OS : x86_64 Ubuntu Linux
C compiler : gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
gcc -O2 weird.c
#include <stdio.h>
int main() {
int i = 0x7fffffff;
int ii = 0x0000000f;
if ((i + 1) < ii)
printf ("yes1 %#x\n", i + 1);
if ((i + 1) == ii)
printf ("yes2 %#x\n", i + 1);
if ((i + 1) > ii)
printf ("yes3 %#x\n", i + 1);
return 0;
}
答案 0 :(得分:7)
在你的情况下(i + 1)溢出整数变量的范围。
事实是,有符号的int变量上的溢出是ANSI标准中的未定义行为,因此严格来说它可能导致任何结果。您的编译器可能符合标准,但任何具有良好计算机理解能力的人都会期望变量会溢出到负值,因为计算机寄存器不会区分有符号/无符号范围。
以下是ANSI标准在Undefined behavior
(以及其他情况)中所说的内容:
以下情况中的行为未定义:
算术运算无效(例如除数或模数为0) 或产生无法在空间中表示的结果 提供(例如溢出或下溢)($ 3.3)。
另一方面,这对无符号类型无效:
涉及无符号操作数的计算可以 永远不会溢出,因为结果无法表示 结果无符号整数类型以模数减少 一个大于可以表示的最大值 得到无符号整数类型。
以下是推荐部分($ 3.3表达式)中的相关部分:
如果在评估表达式期间发生异常(那个 是,如果结果没有数学定义或不可表示), 行为未定义。
答案 1 :(得分:3)
在代码的所有情况下i+1
正在生成有符号整数溢出,这是undefined behavior,这意味着程序可能会出现不可预测的行为。我们可以从draft C99 standard部分6.5
表达式段落 5 中看到(强调我的),这是未定义的:
如果在评估表达式期间发生异常情况(即,如果出现异常情况) 结果在数学上未定义或不在其可表示值的范围内 类型),行为未定义。
这也是C11标准草案中的相同部分。
一种可能的方法是使用clangs -fsanitize=undefined
选项,这是clangs santizer suite部分我们得到以下运行时错误:
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
答案 2 :(得分:2)
我认为你正在遇到一个优化器案例,编译器在这种情况下说整数,x+1>y
可以更有效地计算为x>=y
...而且不幸的是,这通常是正确的,并且是对于无符号值总是如此,这个特殊情况下x + 1包裹为负值会打破这种假设。
但是,由于signed int overflow让我们进入了未定义行为的领域(请参阅@ Marian的回答),这不是错误的。只是出乎意料。
(考虑删除我的答案,但由于它说明了两项测试都是如此,我认为值得保留。)