Jan 192017
 

64비트 Objective-C에 대한 글을 쓰기 앞서서 C 언어 데이터 모델이 무엇인지 이야기하고자 한다. 64비트 시스템이 나오면서 기존의 플랫폼에 따른 타입들의 크기를 재정의 해야할 필요가 생겼는데 이에 대한 이야기이다. 플랫폼에 따라 변하는 기본 타입들은  int, void*(pointer), long, long long 등을 말한다. 물론 16비트 CPU에서 32비트로 전환되던 시절에도 이 이슈는 존재하였다. 예를 들면 16비트 cpu의 경우 16비트의 주소값으로는 65.536Byte 밖에 표현할 수 없는데, 이에 20비트의 포인터를 사용하였었다(모든 기종이 그렇다는 것은 아니다). 여기서 문제는 처리 단위가 16비트이다 보니 segment value(기준 주소를 4비트 시프트)와 offset(segment value로 부터의 실제 좌표의 차이)과 같이 포인터를 좀 더 복잡하게 고민하여 처리해야했다. near pointer와 far pointer로 구분하여 사용하던 시절이 있었다. 어쨋든 32비트에서 64비트로 바뀔 때도 비슷한 이슈가 있었는데, 이 것이 지금 말하려는 C언어 데이터 모델이다.

컴파일러나 플랫폼에 따라 선택한 데이터 모델은 달라진다. 기존 32bit 프로그래밍 모델에서는 ILP32를 사용한다. LP32는 기존 Win16CAPI에서 사용되곤 했다. LLP64의 경우 윈도우에서 채택[2] 했으며, LP64의 경우 일부 유닉스 계열에서 사용한다.

여기서 L은 long에 해당하며, P는 pointer size를 이야기 하며, I는 int를 의미, LL은 long long을 의미한다. long long의 경우 지원하지 컴파일러에 따라 지원하지 않을 수도 있다[2].

Datatype LP64 ILP64 LLP64 ILP32 LP32
char 8 8 8 8 8
short 16 16 16 16 16
int 32 64 32 32 16
long 64 64 32 32 32
long long 64
pointer 64 64 64 32 32

위의 테이블을 보면 각 데이터 모델에 따라서 어떤 값을 가지게 되는지 알 수 있다. pointer의 경우 확실히 다르기 때문에 기존 32bit 코드를 64bit로 변경할 때 꼭 주의 하여야 한다. long type의 변수에 포인터 값을 할당하여 사용하는 경우도 멀티플랫폼을 지원하기위한 개발을 한다거나 할 때 위험하기 때문에 잘 고려해서 선택해야한다.

차라리 C99에서 정확한 사이즈가 지정된 데이터 타입이 추가되었는데, 컴파일러가 C99와 호환된다면 이를 선택하는 것이 좋을 수도 있다. int8_t, uint8_t, int32_t, int64_t 등과 같이 unsigned된 형태와 8,16,32,64를 지원한다. 하지만 문제 점도 있는데, int32_t를 썼는데 16비트 컴퓨터에서 동작시킨다면 성능이 나빠질 수도 있다던지 하기 때문에 상황에 알맞게 구현해야할 것이다. 32비트와 64비트 빌드를 둘 다 지원하는 경우도 마찬가지로 데이터 타입의 사이즈를 고려해야 한다. 또한 size_t인 데이터도 사용할 때 사이즈에 주의해야한다.

참고자료

[1] Unix.org, “64-Bit Programming Models: Why LP64?”,  http://www.unix.org/version2/whatsnew/lp64_wp.html

[2] Hook, B. (2005). Write Portable Code: An Introduction to Developing Software for Multiple Platforms. No Starch Press., pp85-89