Shift Issue.

@codemaru · April 21, 2007 · 3 min read

아래 코드 결과값이 무엇일까요? 대부분 많은 분들이 "00"을 예상하실 겁니다. 하지만 VC++에서 컴파일에서 돌려보시면 실제로 그와같지 않다는 것을 발견하게 될 겁니다. "10"이 나오죠. 왜 그럴까요?

int \_tmain(int argc, \_TCHAR\* argv[])  
{  
    int a = 1;  
    printf("%d %d\n", a << 32, 1 << 32);  
    return 0;  
}

원인을 찾기 위해서는 컴파일러가 어떤 행동을 해서 결과가 다른지 우선 알아야 겠죠. 어셈블리 리스트를 뽑아 보도록 합시다.

; printf("%d %d\n", a << 32, 1 << 32);

push 0
mov eax, DWORD PTR _a$[ebp]
shl eax, 32
push eax
push OFFSET FLAT:$SG9623
call _printf
add esp, 12
리스트를 보면 1 << 32는 컴파일러가 계산을 해서 0값을 집어 넣는 것을 볼 수 있습니다. 그리고 a << 32는 shl 명령어를 통해서 쉬프트한 값을 저장하고 있죠. 그렇다면 이 상황에서 더 궁금한 것은 shl eax, 32의 결과가 왜 0이 아닌 1인가 하는 것 입니다. 왼쪽으로 32번 이동 시키면 모든 비트가 0이 되어야 정상이기 때문입니다. 그런데 왜 1일까요?

답은 IA-32 아키텍처의 명령어 구조에 있습니다. intel의 어셈블리 설명 문서에서 shl을 찾아보면 성능상의 이유로 shl의 경우 31까지만 허용한다고 되어 있습니다. 31보다 큰 경우에는 해당 값의 하위 5바이트만 이용한다고 되어 있죠. 32를 이진수로 표현하면 100000입니다. 하위 5바이트는 0이죠. 따라서 shift를 하나도 하지 않은 원본 값이 그대로 저장되어 있는 겁니다.

shift를 사용할 때에는 항상 주의 하도록 해야 겠습니다. 무심코 사용할 경우 엉뚱한 결과값으로 고생할 수 있습니다.

shift.zip

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중