前回はmultichar定数への警告でした。今回はmultiつながり?で multistatementマクロに対する警告の発出です。C++ならテンプレートというものがあるのでそれに任すのも手なのでしょうが、Cのマクロには多くを期待しない方が良いように思ってます(個人の感想です。)たまに人様の超絶マクロに感動しますが。
※『オプション沼』投稿順indexはこちら
※今回は動作確認に以下を使用しています
-
- Windows11 WSL2上のUbuntu 20.04 LTS、gccのバージョンは9.4.0
マクロのお作法
多分、C言語を習い始めた最初のころにCのマクロの使い方のお作法にはご指導が入るように思うのです。私なんぞは中年になってからCを使い始めた後発で、Cを体系的に習った記憶など無い素人なのですが、以下のように定数を定義するときに丸カッコでくくれ、というお作法は金科玉条のごとくに守っておりますぞ。
#define ABC (1)
一方、以下のようなマルチステートメントなマクロ、今回のターゲットですが、は正直自分じゃ書いたことがありません。多分、やらん方がいい、と言われたまま、何も考えずにやってないだけかと思います。どちらかと言えば、関数定義して inline 展開した方が無難じゃね、という派(そういう派閥があったのか?)
#define DEF x++; y++;
時々、何かのソースの中に行末にバックスラッシいれた長大なマクロを拝見することがあります。中にはすごくカッコイイことをしている場合もあって関心します。でも、慣れないことはやめとこーという保守派です。
#define GHI x++;\ y++;
それでも一応、マルチステートメントなマクロを書くなら「こうせよ」というお作法だけは朧気に記憶しております。こんな感じでよかった筈。
#define JKL do {x++; y++;} while (0)
まあ、マクロのお作法は、人(組織)によりいろいろあるので、結構差異が大きいような気がします。
-Wmultistatement-macros
さて、そんなマルチステートメント・マクロを変なところで使ってしまうと妙なことになるケースがあります。まあ、if とか制御文の後は必ず{ } でくくれとか、お作法が決まっていたら妙なことになったりしないのかも知れませんが。
例によってGNU様のオプションのマニュアルページが以下に。
3.8 Options to Request or Suppress Warnings
今回実験のソース
上記のマニュアルページのほぼほぼパクリです。不注意に使うとマズイところにマクロDEFとGHIを配置してみてます。ABCとJKLは比較用っす。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define ABC (1) #define DEF x++; y++; #define GHI x++;\ y++; #define JKL do {x++; y++;} while (0) int main(int argc, const char *argv[]) { int x = 11; int y = 20; int cond = 0; if (!cond) printf("ABC=%d\n", ABC); printf("before DEF: x=%d y=%d\n", x, y); if (cond) DEF printf("after DEF: x=%d y=%d\n", x, y); if (cond) GHI printf("after GHI: x=%d y=%d\n", x, y); if (cond) JKL; printf("after JLK: x=%d y=%d\n", x, y); return EXIT_SUCCESS; }
ビルドして実行
-Wall とかすれば今回の-Wmultistatement-macrosはその中に含まれているので検出されます。今回は殊更に-Wmultistatement-macrosの有り無しで警告がどうかわるか、眺めてます。
4つあるマクロの展開のうち、ヤバイのはDEFとGHIの2つですが、警告オプションつけるとしっかり指摘が入っているのが分かります。よかった。
あれれ、おかしいなxとyのインクリメント回数が食い違っている。上記みたいなアカラサマな例ならすぐに分かるけれども、そうでないときは結構謎かも。