比较整数时C中的奇怪行为

时间:2017-05-23 07:13:11

标签: c clang

在我的mac环境中遇到此问题,其中gcc版本如下所示:

Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix

代码段来自其中一个函数。

int someFunction(int x, int n) {
    int TMin_n = -(1 << (n-1));
    int TMax_n = (1 << (n-1)) - 1;
    int a = -2147483648;
    printf("%s\n", x == a ? "true" : "false");      // true
    printf("%s\n", x <= TMax_n ? "true" : "false"); // false
    printf("%s\n", a <= TMax_n ? "true" : "false"); // true
    printf("%d %d %d\n", TMin_n, x, TMax_n);        // -2147483648 -2147483648 2147483647
    return 0;
}

a等于x,但为什么它们在与TMax_n比较时有不同的行为?

更新

此代码段中的所有数据类型均为int

UPDATE2

谢谢大家。我刚刚在ubuntu机器上尝试了相同的代码,并且工作正常。它只停留在我的MAC上。这是与编译器有关的一个问题。

2 个答案:

答案 0 :(得分:5)

这似乎是由于表达式(1 << (n-1)) - 1中的未定义行为,特别是在(1 << (n-1))中,因为1被视为int(可能是32位)和表达式然后,(1 << (n-1))会产生一个高于int可表示的最大值的值。所以这个(中间)结果会导致有符号整数算术溢出,即UB(参见cppreference):

  

当有符号整数算术运算溢出时(结果确实如此)   不适合结果类型),行为是未定义的:它可能会换行   根据代表的规则(通常是2&#39; s   补充),它可能会陷入某些平台或由于编译器选项   (例如GCC和Clang中的-ftrapv),或者可以完全优化   编译器。

因此它可能适用于某些编译器,它可能不适用于其他编译器。 但是,如果在bitshift之前强制转换为unsigned int,则溢出将消失,您将返回已定义(和预期)的行为:

(int) (((unsigned)1 << (n-1)) - 1)

BTW:如果你在&#34;其他编译器选项中设置-ftrapv&#34;对于C编译器,表达式int TMin_n = -(1 << (n-1))int TMax_n = (1 << (n-1)) - 1会导致运行时异常(例如EXC_BAD_INSTRUCTION)。

答案 1 :(得分:3)

我使用online clang compiler尝试了您的代码段,并从问题中得到了结果。我假设代码(包括函数调用)完全内联,然后编译器优化它找到的所有比较常量。

有问题的一行似乎是:

int TMax_n = (1 << (n-1)) - 1;

如果我明确地将(1 << (n-1))转换为unsigned,则问题就会消失:

int TMax_n = (int) ((unsigned)(1 << (n-1)) - 1);