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));이렇게 잘 나오겠지요.