C 언어에서 sizeof 연산자를 직접 구현하려면 포인터 산술(pointer arithmetic)을 활용할 수 있습니다. 변수 x가 있을 때 &x는 해당 변수의 메모리 주소를 가리킵니다. 여기서 &x + 1은 단순히 주소 값에 1을 더하는 것이 아니라, x의 데이터 타입 크기만큼 주소를 증가시킵니다.
즉, x가 char 타입이라면 주소가 1바이트만큼 증가하고, int나 float 타입이라면 4바이트만큼 증가합니다. 따라서 (&x + 1)과 &x의 차이를 계산하면 x의 실제 크기를 구할 수 있습니다.
매크로를 사용하는 이유
일반 함수로는 구현할 수 없습니다. 함수에는 인자의 데이터 타입 정보가 전달되지 않기 때문입니다. 그래서 컴파일 시점에 코드가 치환되는 매크로(macro)를 사용해야 합니다.
또한 포인터를 (char*)로 캐스팅하는 것도 중요한 포인트입니다. char 타입은 항상 1바이트를 차지하므로, char 포인터끼리의 주소 차이는 곧 바이트 수를 의미합니다. 즉, 해당 메모리 공간에 몇 개의 char 타입 데이터가 들어갈 수 있는지를 계산하는 것과 같습니다.
예제 코드
#include <stdio.h>
#define my_sizeof(type) (char *)(&type+1)-(char*)(&type)
main(void) {
int x = 10;
char y = 'f';
double z = 254748.23;
printf("size of x: %d\n", my_sizeof(x));
printf("size of y: %d\n", my_sizeof(y));
printf("size of z: %d\n", my_sizeof(z));
}실행 결과
size of x: 4 size of y: 1 size of z: 8
주의 사항
이 방식의 매크로는 타입 이름이 아닌 반드시 변수(lvalue)를 인자로 받아야 합니다. 예를 들어 my_sizeof(int)처럼 타입을 직접 넘기면 컴파일 오류가 발생합니다. 또한 배열 이름에 적용하면 배열 전체 크기가 반환되지만, 함수 매개변수로 전달된 포인터에는 원래 타입의 크기가 아닌 포인터 크기가 반환되므로 사용 시 유의해야 합니다.