C와 C++에는 정수형 데이터를 다루기 위한 네 가지 기본 데이터 타입이 있습니다. 바로 short, int, long, long long입니다. 각 데이터 타입은 서로 다른 크기의 메모리 공간을 차지하며, 그 크기는 CPU 아키텍처와 운영체제에 따라 달라질 수 있습니다.
예를 들어 int 타입은 어떤 환경에서는 4바이트를 차지하지만, 다른 환경에서는 2바이트를 차지하기도 합니다. 이는 컴파일러에 따라서도 달라지는데, 특히 크로스 컴파일러(cross compiler)를 사용하는 경우 그 차이가 두드러집니다.
크로스 컴파일러란?
크로스 컴파일러란 현재 실행 중인 플랫폼이 아닌, 다른 플랫폼을 대상으로 코드를 컴파일할 수 있는 컴파일러를 의미합니다. 예를 들어 x86 Windows 환경에서 ARM 기반 임베디드 시스템용 실행 파일을 만드는 경우가 여기에 해당합니다.
따라서 동일한 소스 코드라도 32비트 시스템과 64비트 시스템에서 컴파일하면 서로 다른 결과를 출력할 수 있습니다. 다음 예제를 통해 확인해 보겠습니다.
예제 코드
#include<stdio.h>
int main() {
printf("Size of int : %ld Bytes\n", sizeof(int));
printf("Size of long : %ld Bytes\n", sizeof(long));
printf("Size of long long : %ld Bytes", sizeof(long long));
}실행 결과
Size of int : 4 Bytes Size of long : 4 Bytes Size of long long : 8 Bytes
데이터 타입별 일반적인 크기
| 데이터 타입 | 32비트 시스템 | 64비트 시스템(Linux) |
|---|---|---|
| short | 2바이트 | 2바이트 |
| int | 4바이트 | 4바이트 |
| long | 4바이트 | 8바이트 |
| long long | 8바이트 | 8바이트 |
위 예제에서 알 수 있듯이, long 데이터 타입의 실제 크기는 컴파일러와 시스템 환경에 따라 달라집니다. 그렇다면 그 이유는 무엇일까요?
long 크기가 달라지는 근본 원인
CPU는 메모리 주소 레지스터(MAR, Memory Address Register)에 주소를 지정하여 주 메모리(RAM)에서 데이터를 호출합니다. 해당 위치의 데이터가 발견되면 메모리 버퍼 레지스터(MBR, Memory Buffer Register)로 전송되고, 이후 연산에 사용하기 위해 CPU 내부 레지스터에 저장됩니다.
여기서 중요한 점은 데이터 버스(data bus)의 폭이 CPU 레지스터의 크기를 결정한다는 것입니다. 32비트 시스템에서는 한 번의 메모리 접근으로 최대 4바이트(32비트)의 데이터만 가져올 수 있습니다. 만약 처리해야 할 데이터가 32비트보다 크다면, 두 번의 메모리 접근 사이클이 필요하게 됩니다.
반대로 작은 데이터(예: short나 int 범위의 값)를 다룰 때는 몇 번의 사이클이든 결과에 큰 차이가 없습니다. 그러나 매우 큰 정수값을 다루어야 하는 상황이라면, 한 번의 사이클로 더 많은 데이터를 처리할 수 있는 long 또는 long long 타입이 필수적입니다. 이것이 C 언어에서 long 계열 데이터 타입이 필요한 핵심적인 이유입니다.