两者如何(i + 1)< ii和(i + 1)>这两个都是真的吗?

时间:2014-03-31 12:21:06

标签: c undefined-behavior integer-overflow

我目前正在学习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;
}

3 个答案:

答案 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的回答),这不是错误的。只是出乎意料。

(考虑删除我的答案,但由于它说明了两项测试都是如此,我认为值得保留。)