5-3-다.sizeof 연산자

다른 연산자들은 모두 +, -, && 같은 기호로 표현하는데 sizeof 연산자는 단어로 되어 있어 조금 특이해 보인다. 이 연산자는 피연산자로 주어진 타입 또는 변수의 크기를 계산한다. 기본 형식은 다음과 같다.

 

sizeof(타입 또는 변수)

 

피연산자로 int, double같은 타입을 쓸 수도 있고 변수를 쓸 수도 있으며 상수를 사용할 수도 있다. 아뭏든 괄호안에 있는 대상이 메모리를 얼마나 차지하고 있는지 계산한다. 다음 예제를 실행해 보면 이 연산자가 어떻게 동작하는지 금방 알 수 있을 것이다.

 

: sizeof

#include <Turboc.h>

 

void main()

{

     int i;

 

     printf("int=%d\n",sizeof(int));

     printf("double=%d\n",sizeof(double));

     printf("i=%d\n",sizeof(i));

     printf("string=%d\n",sizeof("string"));

}

 

정수, 실수 타입과 정수형 변수, 문자열 상수에 대해 크기를 계산해 보았다. 실행 결과는 다음과 같다.

 

int=4

double=8

i=4

string=7

 

정수형은 4바이트를 차지하고 실수형은 8바이트를 차지한다. "string"이라는 문자열은 6자이지만 제일 뒤의 널 종료 문자도 메모리를 차지하므로 크기는 7바이트이다.

sizeof 연산자는 사용자가 직접 계산해야 할 변수의 크기를 컴파일러가 대신 계산해 주는 연산자이다. sizeof(int)의 결과가 4라는 것은 누구나 알고 있는 사실이다. 그러나 만약 이 소스가 16비트와 32비트를 동시에 지원해야 한다면 sizeof(int)는 상황에 따라 2가 될 수도 있고 4가 될 수도 있다. 그때마다 소스를 직접 고치는 것보다는 sizeof(int)라고 써 놓고 컴파일러가 알아서 계산하도록 하는 편이 더 안전하다. sizeof 연산자의 실용적인 사용예는 배열의 크기를 계산할 때이다. 다음과 같은 배열을 사용하고 있다고 하자.

 

int price[100][3];

 

이 배열은 100가지 상품의 세가지 종류(대, 중, 소 등)에 대한 가격 정보를 가지는데 배열의 크기는 100*3이고 정수형 배열이므로 총 1200바이트가 될 것이다. 만약 이 정보를 파일로 저장하거나 배열 크기만큼 메모리를 새로 할당하려면 1200이라는 크기값을 지정해야 할 것이다.

 

파일쓰기(1200바이트);

메모리 할당(1200바이트);

 

이런 식으로 소스에 직접 필요한 크기를 적으면 일단은 제대로 동작한다. 그런데 개발중에 상품의 개수가 100가지에서 120가지로 늘어나고 각 상품이 4가지 종류로 세분되도록 바뀌었다고 하자. 그러면 필요한 price 배열은 int price[120][4]가 될 것이며 이 배열의 크기는 더 이상 1200바이트가 아니다. 배열처럼 개발중에라도 크기가 종종 바뀌는 값은 그 크기를 직접 계산하지 말고 sizeof 연산자를 사용해야 한다.

 

파일쓰기(sizeof(price));

메모리 할당(sizeof(price));

 

이렇게만 써 놓으면 컴파일러가 컴파일할 때마다 알아서 계산하므로 배열의 크기를 바꾸어도 다른 부분은 손 댈 필요가 없어진다. sizeof연산자는 단순한 편리외에도 불일치의 위험을 제거하는 역할도 한다. 위 예에서 1200이라는 수를 직접 쓴 곳이 8군데라고 할 때 수작업으로 고칠 경우 한 곳을 빠뜨릴 위험이 있지만 sizeof연산자를 쓰면 더 이상 이런 걱정을 하지 않아도 된다.

sizeof 연산자는 피연산자의 총 크기를 바이트 단위로 계산한다. int array[34]라는 배열이 있을 때 sizeof(array)는 34*4=136이다. 만약 배열의 총 바이트수가 아닌 배열의 요소 개수, 그러니까 이 경우에 34라는 값을 알고 싶으면 다음과 같이 한다.

 

sizeof(array) / sizeof(array[0])

 

배열 전체 크기를 배열 요소의 크기로 나누면 배열 요소의 개수가 된다. 자주 사용되는 식이므로 외워 두도록 하자.

배열은 그래도 암산으로 그 크기를 구하기가 쉽지만 구조체는 각 멤버 크기의 총합을 구해야 하기 때문에 사람이 직접 그 크기를 계산하는 것은 무척 귀찮고 비생상적인 일이다. 뿐만 아니라 구조체는 정렬방식이라는 컴파일러 옵션에 따라 크기가 약간씩 달라질 수도 있기 때문에 직접 계산하면 틀릴 위험도 있다. 이럴 때는 크기를 직접 계산하지 말고 반드시 sizeof 연산자를 사용해야 한다.

sizeof 연산자는 컴파일시에 컴파일러에 의해 계산되며 그 결과는 정수 상수이다. 타입이나 변수의 크기는 컴파일할 때 미리 알 수 있기 때문에 컴파일러가 컴파일할 때 계산해서 결과 상수를 대신 집어 넣는다. 실행 시간에 계산되는 것이 아니다.

 

arsize = sizeof(array) / sizeof(array[0]);

 

이 문장에서 사용된 두 개의 sizeof는 둘 다 상수이다. 그래서 arsize = 136 / 4;가 되며 상수끼리의 연산도 상수이므로 arsize=34;가 된다. 결국 실행 파일에는 arsize=34라는 대입문이 대신 들어가게 된다. sizeof 연산자를 아무리 과도하게 쓰더라도 실행 시간이 느려지거나 프로그램이 커지는 불이익은 없다. 프로그래머가 해야 할 잡스러운 계산을 컴파일러가 대신하는 것이므로 적극적으로 활용하도록 하자. 부려 먹자는 얘기다.