2012-06-20 1 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 정수 불평등 비교 이것은 출력을 제공

(I 실제로 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

이 엑스 코드 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을 길게 캐스팅하고 해당 기호를 올바르게 처리하지 못하고 있습니까? 혹은 그 반대로도? 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

이것은 오류입니다. too small은 0 이외의 다른 될위한 C 표준의 여지 작동 원리는 없다 : INT_MIN 이후

  1. int, 그것은 "일반적인 산술 변환"동안 long로 변환됩니다. 이는 longint (둘 다 부호 유형 임)보다 순위가 높기 때문에 발생합니다. 모든 피연산자는 적어도 int 등급이므로 프로모션이 발생하지 않습니다. 정의되지 않거나 구현 지정 동작이 호출되지 않습니다.

  2. 변환 중에 INT_MIN의 값이 보존됩니다.int에서 long으로 변환되므로 long의 범위가 적어도 int 인 것으로 보장되므로 변환 중에 INT_MIN의 값을 보존해야합니다. 정의되지 않거나 구현 지정 동작이 호출되지 않습니다. 모듈화되지 않은 유형의 변환 만 허용됩니다.

  3. 0이어야합니다.

광고 확장 또는 다른 것들을위한 흔들림 방이 없습니다. 또한 printf에 대한 호출이 정확하기 때문에 문제가 없습니다.

다른 시스템에서 재생산하거나 재생산 할 수있는 다른 사람에게 보내면 버그를 직접 툴 체인 공급 업체에보고해야합니다. 버그 재현

시도 : 나는 ON과 OFF 최적화 모두 모두, 다음 조합 중 하나에서 문제를 재현 할 수 없습니다 :

  • GCC 4.0, PPC + PPC64
  • GCC 4.2, PPC + PPC64
  • GCC 4.3, 64
  • GCC 4.4, 64
  • 연타 3.0, 64
+4

또한 O0을 사용하여 arch armv7의 Xcode (4.3.2) 툴 체인에서 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 is a compiler bug"를 예약하려하지만 이것은 컴파일러 버그와 같습니다.

+0

C 표준에 따르면, 'int'를 부호를 유지하지 않고 'long'으로 변환하는 것은 오류입니다. 호환되는 C 구현은 그러한 일을 할 수 없습니다. –

+0

'0000002147483647''0000000080000000' – Albert

+0

% 16lx 형식은 부호없는 long int 인수를 필요로합니다. l_int_min은 부호가있는 long으로 전달됩니다. 이 값은 사용하기 전에 부호 확장 된 INT_MIN을 사용하여 초기화되었습니다. – wildplasser