Other Gotchas

C Preprocessor macros and precedence

전처리는 프로그램이 실제적으로 컴파일 되기 전에 수행되는 operation입니다. Preprocessor는 단지 복사-붙여넣기처럼 코드의 그 부분을 대체하는 것입니다.


#define BADD(x,y) x+y
char buffer[BADD(5,5)*2];


위와 같은 코드가 있다면  전처리 이후에 두 번째 라인은 다음과 같이 치환됩니다.

char buffer[5+5*2];


즉, 이렇게 치환된 코드는 곱셈이 덧셈보다 우선순위가 높으므로 buffer[20]이 아닌 buffer[15]가 선언됩니다. 이러한 작동을 막기 위해서는 macro variable을 아래와 같이 반드시 괄호로 감싸주는 것이 필요합니다.

#define ADD(x,y) ((x)+(y))



C preprocessor Macros and Side-Effects

#define min(a,b) ((a)<(b) ? (a) : (b))
int x = 4;
if (min(x++, 100)) printf("%d is six", x);


위와 같은 매크로는 전처리 이후에 다음과 같아집니다

( (x++) < (100) ? (x++) : (100) )

즉, x가 4일때 x와 100을 비교하고 난 다음 x++에 의해 1이 증가됩니다. 그리고 4는 100보다 작으므로 다시 x++를 수행하게 되어 결과적으론 x는 두번 증가해 6이 됩니다.

standard C macro에서 이러한 종류의 부작용을 막는 좋은 방법이 없습니다. 그러나 GCC에서는 해결방법이 존재합니다.


sizeof(type[]) vs sizeof(type *)

#define ARRAY_LENGTH(A) (sizeof((A)) / sizeof((A)[0]))
int fixed_length_array[10]; // ARRAY_LENGTH(fixed_length_array) = 10
int *dynamic_array = malloc(10); // ARRAY_LENGTH(dynamic_array) = 2 or 1


위에서 두번째 라인처럼 고정된 길이로 선언된 배열이 존재한다면 sizeof는 이 배열이 차지하는 총 바이트 수를 반환해줍니다. 즉 위와 같은 보기라면 40바이트를 반환해 ARRAY_LENGHTH는 10이 될 것입니다.

하지만 세번째 라인처럼 pointer의 sizeof는 가리키는 내용의 크기가 아니라 그 주소값을 저장하는 데 필요한 크기를 반환해 줍니다. 즉 32비트라면 4바이트, 64비트라면 8바이트를 반환합니다. 이러한 경우 ARRAY_LENGTH는 2나 1이 반환됩니다.

sizeof를 통해서는 오직 컴파일 타임에 선언되는 array 변수만 실제 array의 크기를 반환합니다.



sizeof and Side-Effects

int a = 0;
size_t size = sizeof(a++);
printf("size: %lu, a: %d", size, a);

위와 같은 코드는 size: 4, a: 1 대신에

size: 4, a: 0

위와 같은 값을 출력할 것입니다.


대부분의 경우 sizeof 안에 expression들은 runtime에 수행되지 않습니다. 왜냐하면 자료형의 크기는 컴파일 타임에 계산되기 때문입니다. 하지만 C99의 variable-length array는 런타임에 크기가 정해지기 때문에 예외로 존재합니다.

'Angrave System Programming > Learning C' 카테고리의 다른 글

Strings and Structs(2)  (0) 2019.01.09
Strings and Structs(1)  (0) 2019.01.09
Common Gotchas(2)  (0) 2019.01.09
Common Gotchas(1)  (0) 2019.01.09
Text Input And Output(2)  (0) 2019.01.08
Posted by 몰랑&봉봉
,