在我的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上。这是与编译器有关的一个问题。
答案 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);