(C프로그램) 매크로 정의시 안전한 방법

Posted at 2010/04/20 10:31 // in Programming // by Daniel

do { ... } while(0)로 묶기

http://kernelnewbies.org/FAQ/DoWhile0, http://kldp.org/node/41390, http://blog.dasomoli.org/220

안전한 방법은 do{}while(0)로 묶는 것입니다.

#define foo(x) do{ printf(“it’s %d\n”, x); \
                 do_something(x);\
               } while (0)

일반적으로 C에서 매크로를 짜면

#define FOO(x) \
        printf("arg is %s\n", x); \
        do_something_useful(x);

이런 식으로 짜게 됩니다.

그러나 이런 방식은 맹점이 있습니다.

예를 들어

        if (blah == 2)
                FOO(blah);

이렇게 쓰면

        if (blah == 2)
                printf("arg is %s\n", blah);
                do_something_useful(blah);;

이렇게 해석돼 버립니다.

만일 do{ … }while(0)로 만들었다면

if (blah == 2)
        do {
                printf("arg is %s\n", blah);
                do_something_useful(blah);
        } while (0);

이렇게 원하는 대로 해석됩니다.

그렇다고

        #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

이렇게 쓰면

if (x > y)
        exch(x,y);          // Branch 1
else 
        do_something();     // Branch 2

이런 문장이

if (x > y) {                // Single-branch if-statement!!!
        int tmp;            // The one and only branch consists
        tmp = x;            // of the block.
        x = y;
        y = tmp;
}
;                           // empty statement
else                        // ERROR!!! "parse error before else"
        do_something();
이렇게 해석돼 버립니다. –> 컴파일러 에러 발생.
그러므로 do {} while(0)로 묶는 게 최고죠. 그래서 리눅스 커널에서 모든 매크로가 그렇게 돼 있는 겁니다.

매크로에서 쓰는 변수에는 괄호를 꼭 쳐주세요

그리고 한가지 더
매크로에서 쓰는 변수에는 괄호를 꼭 쳐주세요 http://www.oualline.com/style/c06.html

/* Square a number */
#define SQUARE(X) (x * x)
/* Bad practice, no () around parameter */

이렇게 정의하면
a = SQUARE(1 + 3);
-->:
a = (1 + 3 * 1 + 3);
이렇게 돼 버려서 원치 않는 결과가 나옵니다.
/* Square a number */
#define SQUARE(X) ((x) * (x))
이러면
a = ((l + 3) * (1 + 3));
이렇게 잘 나오겠지요.
크리에이티브 커먼즈 라이센스
Creative Commons License