奇怪的C整数不等式比较结果 [英] strange C integer inequality comparison result

查看:23
本文介绍了奇怪的C整数不等式比较结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#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',有一个检查 ival < INT_MIN 对我来说总是正确的.另见 带有进一步参考的测试用例源.)

(I actually got hit by this problem/bug in CPython 2.7.3 in getargs.c:convertsimple. If you look up the code, in case 'i', there is the check ival < INT_MIN which was always true for me. See also the test case source with further references.)

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

Well, I tested a few different compilers now. GCC/Clang, compiled for x86 all return the expected (too small: 0). The unexpected output is from the Clang in the Xcode toolchain when compiled for armv7.

如果你想重现:

这是确切的编译命令:/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

这是 Xcode 4.3.2.

This is Xcode 4.3.2.

我将生成的 a.out 复制到我的 iPhone 并执行它.

I copied the resulting a.out over to my iPhone and executed it.

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

If anyone is interested in the assembler code generated by this:

    .section    __TEXT,__text,regular,pure_instructions
    .section    __TEXT,__textcoal_nt,coalesced,pure_instructions
    .section    __TEXT,__const_coal,coalesced
    .section    __TEXT,__picsymbolstub4,symbol_stubs,none,16
    .section    __TEXT,__StaticInit,regular,pure_instructions
    .syntax unified
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  2
    .code   16
    .thumb_func _main
_main:
    push    {r7, lr}
    mov r7, sp
    sub sp, #20
    movw    r0, #65535
    movt    r0, #32767
    movs    r1, #0
    movt    r1, #0
    str r1, [sp, #16]
    str r1, [sp, #12]
    ldr r1, [sp, #12]
    ldr r2, [sp, #12]
    cmp r2, r0
    movw    r0, #0
    it  gt
    movgt   r0, #1
    and r0, r0, #1
    ldr r2, [sp, #12]
    cmn.w   r2, #-2147483648
    movw    r2, #0
    it  lt
    movlt   r2, #1
    and r2, r2, #1
    mov r3, sp
    str r2, [r3, #4]
    str r0, [r3]
    mov.w   r2, #-2147483648
    mvn r3, #-2147483648
    movw    r0, :lower16:(L_.str-(LPC0_0+4))
    movt    r0, :upper16:(L_.str-(LPC0_0+4))
LPC0_0:
    add r0, pc
    blx _printf
    ldr r1, [sp, #16]
    str r0, [sp, #8]
    mov r0, r1
    add sp, #20
    pop {r7, pc}

    .section    __TEXT,__cstring,cstring_literals
L_.str:
    .asciz   "ival: %li, min: %i, max: %i, too big: %i, too small: %i\n"


.subsections_via_symbols

推荐答案

这是一个错误.在 C 标准中,too small 不能为 0 以外的任何值.这是它的工作原理:

This is an error. There is no room in the C standard for too small to be anything other than 0. Here's how it works:

  1. 由于 INT_MIN 是一个 int,它在通常的算术转换"期间被转换为 long.发生这种情况是因为 long 的排名高于 int(并且两者都是有符号类型).不会发生提升,因为所有操作数都至少具有 int 等级.不会调用未定义或实现指定的行为.

  1. Since INT_MIN is an int, it gets converted to long during the "usual arithmetic conversions". This happens because long has higher rank than int (and both are signed types). No promotions occur, since all of the operands have at least int rank. No undefined or implementation-specified behavior is invoked.

在转换过程中,INT_MIN 的值被保留.由于是从int转为long,保证long至少有int的范围>,在转换过程中必须保留INT_MIN的值.不会调用未定义或实现指定的行为.不允许进行模块化转换,仅适用于无符号类型.

During conversion, the value of INT_MIN is preserved. Since it is being converted from int to long, and it is guaranteed that long has at least the range of int, the value of INT_MIN must be preserved during the conversion. No undefined or implementation-specified behavior is invoked. No modular conversions are permitted, those are for unsigned types only.

比较的结果应该是0.

没有用于标志扩展或其他此类事情的回旋余地.另外,由于对 printf 的调用是正确的,所以那里没有问题.

There is no wiggle room for sign extension or other such things. Also, since the call to printf is correct, there is no problem there.

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

If you can reproduce it on another system, or send it to someone else who can reproduce it, you should report the bug directly to your toolchain vendor.

尝试重现错误:我无法在以下任何组合上重现该行为,所有这些都启用和禁用优化:

Attempts to reproduce the bug: I was not able to reproduce the behavior on any of the following combinations, all both with optimization on and off:

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

这篇关于奇怪的C整数不等式比较结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆