2010-02-16 9 views
2

다음을 인쇄 할 때 -1이되는 이유는 무엇입니까?% d를 사용하여 unsigned long long을 인쇄하십시오.

unsigned long long int largestIntegerInC = 18446744073709551615LL; 

printf ("largestIntegerInC = %d\n", largestIntegerInC); 

은 내가 대신 dllu을 사용해야 알아,하지만 내가 왜합니까 -1 대신 18446744073709551615LL의?

오버플로 때문입니까?

+0

아래의 모든 대답은 추측입니다. ** 아무것도 정의되지 않은 동작 **이 허용됩니다. – Jens

답변

4

C (99), LLONG_MAX에서 long long int 유형의 최대 값은 적어도 9223372036854775807이되도록 보장됩니다. unsigned long long int의 최대 값은 적어도 18446744073709551615, 즉 2 − 1 (0xffffffffffffffff)이되도록 보장됩니다.

그래서

, 초기화해야한다 :

unsigned long long int largestIntegerInC = 18446744073709551615ULL; 

합니다 (ULL 참고.) largestIntegerInC 유형 unsigned long long int이기 때문에, 당신은 "%llu"입니다 올바른 형식 지정자로 인쇄해야합니다

$ cat test.c 
#include <stdio.h> 

int main(void) 
{ 
    unsigned long long int largestIntegerInC = 18446744073709551615ULL; 
    /* good */ 
    printf("%llu\n", largestIntegerInC); 
    /* bad */ 
    printf("%d\n", largestIntegerInC); 
    return 0; 
} 
$ gcc -std=c99 -pedantic test.c 
test.c: In function ‘main’: 
test.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’ 

위의 두 번째 printf()이 잘못되어 아무 것도 인쇄 할 수 없습니다. "%d"을 사용하고 있습니다. 즉, printf()int이지만, 과 거의 같은 크기가 아닌 unsigned long long int이 표시됩니다. 출력으로 -1을 얻는 이유는 (불운) 행운 때문이며 컴퓨터에서 숫자가 2의 보수 표현을 사용하여 표현된다는 사실 때문입니다.나에게 -1 -1 42을 제공 "%d %d %d"으로 프로그램을 실행, 내 맥북에

#include <stdio.h> 
#include <stdlib.h> 
#include <limits.h> 

int main(int argc, char *argv[]) 
{ 
    const char *fmt; 
    unsigned long long int x = ULLONG_MAX; 
    unsigned long long int y = 42; 
    int i = -1; 
    if (argc != 2) { 
     fprintf(stderr, "Need format string\n"); 
     return EXIT_FAILURE; 
    } 
    fmt = argv[1]; 
    printf(fmt, x, y, i); 
    putchar('\n'); 
    return 0; 
} 

및 리눅스 머신, 같은 프로그램에서 :


은의 다음과 같은 프로그램을 실행할 수 있도록,이 나쁠 수있는 방법을 보려면 같은 형식으로 나에게 -1 42 -1을 준다. 죄송합니다. 당신이 당신의 largestIntegerInC 변수에 가장 큰 unsigned long long int 번호를 저장하려는 경우


사실, 당신은 limits.h을 포함 ULLONG_MAX를 사용해야합니다. 또는 당신은 당신의 변수에 -1을 assing 저장해야합니다 :

#include <limits.h> 
#include <stdio.h> 

int main(void) 
{ 
    unsigned long long int largestIntegerInC = ULLONG_MAX; 
    unsigned long long int next = -1; 
    if (next == largestIntegerInC) puts("OK"); 
    return 0; 
} 

을 위의 프로그램에서 두 largestIntegerInCnextunsigned long long int 유형에 대해 가능한 최대 값을 포함한다.

1

2의 보수 연산에서 부호있는 값 -1은 가장 큰 부호없는 값과 같습니다.

는 2의 보수에 음수 비트 패턴을 고려 (I 8 개 비트 정수를 사용하고 있습니다,하지만 패턴은 크기에 관계없이 적용) :

0 - 0x00 
-1 - 0xFF 
-2 - 0xFE 
-3 - 0xFD 

그래서, 당신은 부정적인 일이있다 볼 수 있습니다 가장 큰 부호없는 값에 대한 비트 패턴이기도 한 모든 1의 비트 패턴.

0

부호가있는 32 비트 숫자 형식을 사용 했으므로 -1이됩니다. printf()은 전달한 숫자의 크기를 내부적으로 알 수 없으므로 varargs 목록의 처음 32 비트를 가져 와서 인쇄 할 값으로 사용합니다. 서명 된 형식을 제공 했으므로 그 방식으로 인쇄하고 0xffffffff는 -1의 2의 보수 표현입니다.

3

모든 비트가 1로 설정된 숫자를 전달하기 때문입니다. 2의 보수 기호로 해석되면 -1로 계산됩니다. 이 경우 64 비트가 아닌 32 비트 중 32 비트가 대상이 될 수 있지만 실제로 차이는 없습니다.

0

컴파일러 경고의 이유를 볼 수 있습니다. 그렇지 않으면 가장 높은 경고 수준을 설정하십시오. VS에서는 경고 메시지가 나타납니다. C4245 : '초기화': '__int64'에서 'unsigned __int64'로의 변환, 부호가 있거나 서명되지 않은 불일치.

0

아니요, 오버플로가 없습니다. 이것은 전체 값을 인쇄하지 않기 때문입니다.

18446744073709551615는 0xFFFFFFFFFFFFFFFF와 같습니다. printf %d이 처리 할 때 변환을 위해 32 비트 (또는 64 비트 CPU 인 경우 64 비트) 만 가져오고 이는 부호있는 값 -1입니다.

printf 변환이 %u 인 경우 4294967295 (32 비트) 또는 18446744073709551615 (64 비트)로 표시됩니다.

오버플로는 값이 할당 된 저장소에 맞지 않는 지점까지 증가하는 경우입니다. 이 경우 값은 이고 할당 된 숫자는입니다. 입니다.

관련 문제