1. 상황
CS:APP 그림 2.19와 연습문제 2.21에 TMin32가 -2147483647-1으로 적혀있다. 왜 -2147483648, 0x80000000와 같이 적지 않았을까? C 헤더인 “limits.h”를 잘 살펴보자. TMin32, TMax32가 다음과 같이 표현되어 있다.
1
2
3
/* Minimum and maximum values a ‘signed int’ can hold. */
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
흥미로운 점은 2의 보수 표현 방법과 TMin32를 이상하게 쓰게 만드는 C의 변환 방법의 불균형이다. 이 문제점을 이해하기 위해서는 C언어 표준의 어두운 구석을 파헤쳐 봐야 한다는 것이다. 이런 행위는 Integer 데이터 타입과 표현에 있어서 중요한 세부 요소들을 파악하는 데 도움을 줄 것이다.
TMin32를 -2147483648이라 쓰고 32bit 프로그램으로 컴파일하는 경우를 생각해 보자, CS:APP 그림 2.9(p60, 데이터 사이즈에 관한 내용)와 같이 말이다. 컴파일러가 -X와 같은 형태의 숫자를 접한다면 일단 첫 번째로 숫자의 데이터 타입을 결정하고, 두 번째로 값 X를 입력 후 음수로 바꾸게 된다. 값 2,147,483,648은 TMax32보다 1이 큰 이상 데이터 타입 int로 표현하게는 너무 크다. (불균형 문제 발생)
Figure 1: 정수 상수를 표현하기 위한 데이터 타입들, 언어의 버전과 포맷(10진법, 16진법)에 따라서, 위 리스트 중 제일 먼저 만족하는 타입을 상수의 데이터 타입으로 사용한다.
Figure 2: TMin32 표현에 상수의 데이터 타입. 언어의 버전과 포맷(10진법, 16진법)에 따라서, 우리는 2개의 표현으로 3개의 다른 데이터 타입을 얻을 수 있었다, 그 값이 양수인 경우까지 포함해서 말이다.
컴파일러는 이 값을 정상적으로 표현할 수 있는 데이터 타입을 결정할 것이다.1 컴파일러는 Figure 1의 표에서 언어 버전에 맞는 데이터 타입을 찾을 것이다. 언어의 버전이 ISO C90일 경우, int → long → unsigned 순으로 진행된다. int, long은 2,147,483,648값을 표현하지 못하므로 unsigned로 타입이 결정된다. CS:APP 글 2.3.3에서 봤듯이 값 2,147,483,648와 -2,147,483,648은 32bit 숫자로서 같은 비트 표현을 하고 있으며, 따라서 결과값은 2,147,483,648이며 데이터 타입은 unsigned가 된다. 이번에는 ISO C99의 경우다. 컴파일러는 int → long → long long 순으로 2,147,483,648을 표현할 수 있는 데이터 타입을 찾게 된다. 단, 64bit 에서는 2,147,483,648와 -2,147,483,648를 따로따로 표현할 수 있다. 따라서 결과값은 -2,147,483,648이며 데이터 타입은 long long이다.
16진수 값 0x80000000을 32bit 프로그램으로 컴파일하면, 위와 비슷하게 작동한다. Figure 1에서 16진수에 해당하며 두 언어 버전 모두 사이즈가 만족하는 unsigned가 선택되며 값은 0x80000000이 된다.
이런 번형 등은 Figure 2에 정리되어 있다. 결과가 long, long long인 경우 값이 음수가 된다. 하지만 이건 64bit 길이일 때이며 결과 타입이 unsigned인 경우 값은 양수이고 32bit 길이이다. 이런 결과는 다음 코드로 증명된다.
1
2
int dpos32 = (-2147483648 > 0);
int hpos32 = (0x80000000 > 0);
위 코드는 TMin32를 10진수와 16진수로 표현하며 0보다 큰지 테스트하는 코드이다. 컴파일러와 word 사이즈에 따라서 dpos32 값은 1 또는 0이 된다. 이것은 값이 음수인지 양수인지 나타내는 것이다. 하지만 hpos32는 계속 1로 유지되고 있다. 즉 계속 양수라는 뜻이다. 이것을 보아 TMin32를 작성하는 것은 예상보다 어려운 것이었다.
2. 함의
많은 프로그램에서 word 크기와 언어 표준에 애매함은 프로그램의 행동에 영향을 미치지 못한다. 하지만 이제 우리는 왜 TMin32를 -2147483647-1로 쓰는지 알게 되었다. 2147483647이 TMax32인 이상, 이 표현은 int 데이터 타입으로 표현할 수 있다. 또한 이런 이유로 Figure 1와 같은 변환 규칙을 무시할 수 있다.
-
CS:APP3e 에서는 long long 타입을 다루지 않는다. 이 타입은 최소 64bit 타입으로 ISO C99에 소재 된다. ↩