warning: macro expands to multiple statements
警告:マクロは複文に展開される
[-Wmultistatement-macros]
■複文マクロは危険
#include <stdio.h>
void foo() {puts("foo");}
void bar() {puts("bar");}
void baz() {puts("baz");}
#define MACRO_3Line() foo();bar();baz();
int main(int argc,char *argv[]){
if(argc == 3)
MACRO_3Line() ;
}
MACRO_3line()のマクロ定義部分を波括弧で囲っていないので、
マクロを展開するとbar()とbaz()がif文のthen節からはみ出ます。
■マクロを波括弧で囲む
#include <stdio.h>
void foo() {puts("foo");}
void bar() {puts("bar");}
void baz() {puts("baz");}
#define MACRO_3Line() {foo();bar();baz();}
int main(int argc,char *argv[]){
if(argc == 3)
MACRO_3Line() ;
else {
;
}
}
単純に関数マクロの定義部と参照部を波括弧で囲めば問題は発生しませんが
このコードのように、
マクロ呼び出しのif文then節に波括弧がないと
コンパイルエラーになってしまします。
以下のコマンドでマクロ展開すると
コンパイルエラーになる理由がわかります。
gcc xxx.c -E | indent -kr
※xxx.c は展開したいファイル名
■do-while(0)マクロは奇妙
#include <stdio.h>
void foo() {puts("foo");}
void bar() {puts("bar");}
void baz() {puts("baz");}
#define MACRO_3Line() do{foo();bar();baz();}while(0)
int main(int argc,char *argv[]){
if(argc == 3)
MACRO_3Line() ;
else {
;
}
}
複数の文からなるマクロを
do-while(0) ループで包む事を
メジャールールで推薦していますが、
回らないループって奇妙じゃないですか?
トリッキーな技なので
このサイトでは推奨しません。
※このdo-while(0)で囲むとif文のthen節で
波括弧が無くてもコンパイルエラーにならないのがこの技の売りです。
■inline関数がお勧め
#include <stdio.h>
void foo() {puts("foo");}
void bar() {puts("bar");}
void baz() {puts("baz");}
static inline void MACRO_3Line(void){
foo();
bar();
baz();
}
int main(int argc,char *argv[]){
if(argc == 3)
MACRO_3Line() ;
else {
;
}
}
関数マクロは予期せぬ副作用(予期せぬマクロ展開)があるので、
関数マクロはそもそも推奨しません。
関数マクロを避けて、
inline 関数を使いましょう。
■inline関数はMISRA-Cルールで禁止されている?
と言う場合は
最新のルールを確認しましょう。
2012年度版では inline 関数は解禁されています。
参考:
PRE00-C. 関数形式マクロよりもインライン関数やスタティック関数を使う
https://www.jpcert.or.jp/sc-rules/c-pre00-c.html