15
#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

そんなことがあるものか?

(私は実際に CPython 2.7.3 のこの問題/バグに見舞わましたgetargs.c:convertsimplecase 'i'ival < INT_MIN


さて、私はいくつかの異なるコンパイラをテストしました。x86 用にコンパイルされた GCC/Clang はすべて、期待される値を返します (小さすぎる: 0)。予期しない出力は、armv7 用にコンパイルされたときの Xcode ツールチェーンの Clang からのものです。


再現したい場合:

これは正確なコンパイル コマンドです。/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 です。

a.out結果をiPhoneにコピーして実行しました。

これによって生成されたアセンブラ コードに興味がある場合:

    .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
4

2 に答える 2

5

これはエラーです。too smallC 標準には、0 以外の値を指定する余地はありません。次のように動作します。

  1. INT_MINは であるため、「通常の算術変換」中にintに変換されます。longこれは、longがよりもランクが高いint(両方とも符号付きの型である) ために発生します。すべてのオペランドに少なくともintランクがあるため、昇格は発生しません。未定義または実装固有の動作は呼び出されません。

  2. 変換中、 の値INT_MINは保持されます。intは からに変換されており、 は少なくとも の範囲を持っているlongことが保証されているため、変換中にの値を保持する必要があります。未定義または実装固有の動作は呼び出されません。モジュラー変換は許可されていません。これらは unsigned 型のみです。longintINT_MIN

  3. 比較の結果は になります0

看板の延長などの小刻みの余地はありません。また、への呼び出しprintfは正しいのでそこは問題ありません。

別のシステムで再現できる場合、または再現できる人に送信できる場合は、ツールチェーン ベンダーにバグを直接報告する必要があります。

バグの再現の試み:最適化をオンとオフの両方で、次の組み合わせのいずれかで動作を再現できませんでした。

  • GCC 4.0、PPC + PPC64
  • GCC 4.2、PPC + PPC64
  • GCC 4.3、x64
  • GCC 4.4、x64
  • クラン 3.0、x64
于 2012-06-20T23:22:36.790 に答える
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()。これは、 と同様に、そのプラットフォームでは 32 ビットで0000002147483647あることを意味します。したがって、 anを a にキャストしても、実際には何も変化しないはずです。longintintlong

私は最後の手段として「これはコンパイラのバグです」と保留しようとしますが、これは私にはコンパイラのバグのように見えます。

于 2012-06-20T23:10:11.050 に答える