2012-06-20 6 views
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); 
} 

これは、出力が得られます。奇妙C整数不等比較結果

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

可能ということですどのように?

(私は実際にgetargs.cではCPython 2.7.3でこの問題/バグに見舞われました:。convertsimpleあなたはコードを見てみると、case 'i'で、いつも私のために本当だったチェックival < INT_MINありtest case source with further referencesも参照してください。 。)


まあ、私は今いくつかの異なるコンパイラをテストしました。 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 
+0

キャスティングの変種かもしれませんか? INT_MINをlongにキャストしていて、符号を正しく処理できない可能性がありますか?またはその逆? O.o – TheZ

+0

@Albert興味深いことに、ival:0、min:-2147483648、max:2147483647、too big:0、too small:0' –

+0

printfの%iフォーマットはないと思います。おそらく%dが必要です。そして、printfのようなvarargs関数の引数を明示的にintにキャストするのは良い習慣です。 (この場合、(a> bの値はint型にデフォルト設定されているので)必要ありません。 – wildplasser

答えて

5

これはエラーです。 0以外の何でもするtoo smallのためのC規格の余地はここにそれがどのように動作するかだんがあります:

  1. INT_MINintあるので、それは「通常の算術変換」中にlongに変換されます。これは、longintより上位です(両方とも署名型です)。すべてのオペランドが少なくともintのランクを持つため、プロモーションは行われません。未定義または実装指定の動作は呼び出されません。

  2. 変換時には、INT_MINの値が保持されます。intからlongに変換されており、longの範囲が少なくともintであることが保証されているため、変換中にINT_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の
+4

また、私は、Armolv7用のXcode(4.3.2)ツールチェーン内の-Onを使ってClangで再現することもできます。最適化を行うと、期待通りの結果が得られます。実際のバグのようです。私はそれを報告した。 – Albert

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を小さくします。

EDIT:さて、最初printf()の結果は、0000002147483647longちょうどintなど、そのプラットフォーム上で32ビットであることを意味します。したがって、intlongにキャストしても、実際には何も変更してはいけません。

私は最後の手段として "it's a compiler bug"を予約しようとしていますが、これは私にとってはコンパイラのバグのようです。

+0

Cの標準によれば、符号を保存せずに 'int'を' long'に変換するのはエラーです。準拠したC実装はこのようなことを行うことはできません。 –

+0

'0000002147483647'' 0000000080000000' – Albert

+0

%16lx形式では、unsigned long int引数が必要です。 l_int_minは符号付きlongとして渡されます。その値は、使用前に符号拡張されたINT_MINを使用して初期化されました。 – wildplasser