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

xid*_*dui 3 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
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

更新:

此代码段中的所有数据类型都是int.

更新2:

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

Ste*_*ner 5

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

当有符号整数算术运算溢出时(结果不适合结果类型),行为是未定义的:它可能根据表示的规则(通常是2的补码)回绕,它可能在某些平台上陷阱或由于编译器选项(例如GCC和Clang中的-ftrapv),或者可以由编译器完全优化.

所以它可能适用于某些编译器,它可能不适用于其他编译器.但是,如果你unsigned int在bitshift之前进行转换,溢出就会消失,你又回到了定义的(和预期的)行为:

(int) (((unsigned)1 << (n-1)) - 1)
Run Code Online (Sandbox Code Playgroud)

BTW:如果设置-ftrapv在"其他编译器选项"的C编译器,则表达式int TMin_n = -(1 << (n-1))int TMax_n = (1 << (n-1)) - 1导致运行时异常(如EXC_BAD_INSTRUCTION).