対策1 if文の中にマクロを使うときは{}を使う
複数行のマクロをif文の中で使うときは、if文で{}を使うと安全度が増します。
例えば、下記のソースコードがあったとします。
$ cat sample.c
#include <stdio.h>
#define SUCCESS 1
#define FALSE 0
#define TEST_PRINT(...) printf(__VA_ARGS__)
#define TEST_PRINT_ERROR(status) if((status)){\
printf("OK\n");\
}else{\
printf("NG\n");\
}
int main(){
#if 0
//コンパイルNG
if(SUCCESS)
TEST_PRINT_ERROR(1);
else
TEST_PRINT("NG\n");
#endif
#if 1
//コンパイルOK
if(SUCCESS){
TEST_PRINT_ERROR(1);
}else{
TEST_PRINT("NG\n");
}
#endif
return 0;
}
下記の部分はコンパイルエラーとなります。
//コンパイルNG
if(SUCCESS)
TEST_PRINT_ERROR(1);
else
TEST_PRINT("NG\n");
下記が実際のエラーです。
$ gcc -o sample sample.c
sample.c:18:3: warning: add explicit braces to avoid dangling else [-Wdangling-else]
TEST_PRINT_ERROR(1);
^
sample.c:9:14: note: expanded from macro 'TEST_PRINT_ERROR'
}else{\
^
sample.c:19:2: error: expected expression
else
^
1 warning and 1 error generated.
if文で{}を使うとコンパイルが通ります。
//コンパイルOK
if(SUCCESS){
TEST_PRINT_ERROR(1);
}else{
TEST_PRINT("NG\n");
}
対策2 マクロをdo{}while(0)で囲む
マクロをdo{}while(0)で囲むと、先程の{}がないif文でもコンパイルが通ります。
こちらの方がより安全ですね。
先程のマクロをdo{}while(0)で囲みます。
コンパイルが通りますね。
ただ、そもそも、if文では{}をつけるのが良いとは思いますね。
$ cat sample2.c
#include <stdio.h>
#define SUCCESS 1
#define FALSE 0
#define TEST_PRINT(...) printf(__VA_ARGS__)
#define TEST_PRINT_ERROR(status) do{if((status)){\
printf("OK\n");\
}else{\
printf("NG\n");\
}\
}while(0)
int main(){
if(SUCCESS)
TEST_PRINT_ERROR(1);
else
TEST_PRINT("NG\n");
return 0;
}
