奇怪的C整数不等式比较结果

时间:2012-06-20 22:57:02

标签: c arm

#include <limits.h>
#include <stdio.h>
int main() {
    long ival = 0;
    printf("ival: %li, min: %i, max: %i, too big: %i, too small: %i\n",
           ival, INT_MIN, INT_MAX, ival > INT_MAX, ival < INT_MIN);
}

这给出了输出:

ival: 0, min: -2147483648, max: 2147483647, too big: 0, too small: 1

这怎么可能?

(我实际上遇到了getargs.c convertsimple中CPython 2.7.3中的这个问题/错误。如果您在case 'i'中查找代码,则会检查{ {1}}这对我来说总是如此。另见test case source with further references。)


好吧,我现在测试了几个不同的编译器。为x86编译的GCC / Clang都返回预期的(太小:0)。当编译为armv7时,意外输出来自Xcode工具链中的Clang。


如果您想重现:

这是确切的编译命令:ival < INT_MIN

这是Xcode 4.3.2。

我将生成的/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk test-int.c复制到我的iPhone并执行了。

如果有人对由此生成的汇编程序代码感兴趣:

a.out

2 个答案:

答案 0 :(得分:5)

这是一个错误。 {C}标准中too small没有空间为0以外的任何其他内容。以下是它的工作原理:

  1. 由于INT_MINint,因此在“通常的算术转换”期间它会转换为long。发生这种情况是因为long的排名高于int(两者都是签名类型)。由于所有操作数的排名至少为int,因此不会进行任何促销。未调用未定义或实现指定的行为。

  2. 转换期间,会保留INT_MIN的值。由于它已从int转换为long,并且保证long的范围至少为int,因此INT_MIN的值必须为转换期间保留。未调用未定义或实现指定的行为。不允许进行模块化转换,仅适用于无符号类型。

  3. 比较结果应为0

  4. 没有摆动符号扩展或其他此类事物的余地。此外,由于对printf的调用是正确的,因此没有问题。

    如果您可以在其他系统上重现它,或将其发送给可以重现它的其他人,您应该直接向您的工具链供应商报告该错误。

    尝试重现该错误:我无法重现以下任何组合的行为,所有这两种组合都有优化开启和关闭:

    • GCC 4.0,PPC + PPC64
    • GCC 4.2,PPC + PPC64
    • GCC 4.3,x64
    • GCC 4.4,x64
    • Clang 3.0,x64

答案 1 :(得分:1)

这是什么印刷品?

#include <limits.h>

printf("%016ld\n", LONG_MAX);

long l_int_min = (long)INT_MIN;
printf("%016lx\n", l_int_min);

我想知道INT_MIN是否在没有签名延伸的情况下被强制转移到long。这将使0小于结果值。

编辑:好的,第一个printf()的结果是0000002147483647,这意味着long在该平台上是32位,就像int一样。因此,将int投射到long实际上不应该改变任何内容。

我尝试保留“这是一个编译器错误”作为最后的手段,但这对我来说看起来像编译器错误。