2012-01-19 7 views
5

내가 작성한 일부 C 코드에서 버그가 발생했습니다. 상대적으로 수정하기가 쉽지만 더 좋은 문제를 이해할 수 있기를 바랍니다. 근본적으로 어떤 일이 일어 났는가? 나는 모듈러스 연산이 적용될 때 음수의 부호없는 동등 물, 래핑되어 "큰"숫자 인 부호없는 정수 (uint32_t, 사실)를 가졌다.C에서 모듈러스 연산자로 부호없는 오버플로

#include <stdio.h> 
#include <stdint.h> 

int main(int argc, char* argv[]) { 

    uint32_t foo = -1; 
    uint32_t u = 2048; 
    uint64_t ul = 2048; 

    fprintf(stderr, "%d\n", foo); 
    fprintf(stderr, "%u\n", foo); 
    fprintf(stderr, "%lu\n", ((foo * 2600000000) % u)); 
    fprintf(stderr, "%ld\n", ((foo * 2600000000) % u)); 
    fprintf(stderr, "%lu\n", ((foo * 2600000000) % ul)); 
    fprintf(stderr, "%lu\n", foo % ul); 

    return 0; 

} 

를이 내 x86_64의 시스템에서, 다음과 같은 출력을 생성합니다 : 여기 예제 프로그램을 설명하는 것입니다

-1 
4294967295 
18446744073709551104 
-512 
1536 
2047 

1536

내가 기대 한 수는 있지만 (uint32_t가) (- 512)입니다 당신이 상상할 수 있듯이, 나는 약간의 것을 던져 버렸습니다.

제 질문은 이것입니다. 왜이 경우 서명되지 않은 두 숫자 사이의 모듈러스 연산이 제수 (즉, 음수)보다 큰 숫자를 생성합니까? 이 행동이 선호되는 이유가 무엇입니까?

+1

2600000000은 int (또는 int 길이 또는 long long 64 비트)이며 곱셈 결과가 (부호가있는) long이 될 수 있습니다. 어떤 플랫폼을 사용하고 계십니까? – Random832

답변

3

나는 이유는이 부호있는 32 비트 INT에 적합하지 않기 때문에 컴파일러는, 서명 된 64 비트 숫자로 2600000000 문자를 해석하는 것을 생각하십시오. 숫자를 2600000000U으로 바꾸면 예상 한 결과를 얻어야합니다.

+2

실제로 OP는 잘못된 형식 문자열을'printf'에 전달하여 UB를 호출했습니다. –

2

참고 자료가 없지만 두 배의 피연산자를 부호있는 정수 형식으로 강제 변환해야하므로 승법을 수행 할 때 int64_t으로 승격됩니다. 2600000000u 대신 2600000000 ....

관련 문제