めのん@ひとりプログラミング同好会

このブログはすべてフィクションであり、実在の人物、団体とは一切関係ありません

可変個引数マクロを究める!(その1)

こんばんは、めのんです。

先日から「私はCが好き」とか「私はCが得意」とか言っているのに、Cの具体的な話題が出てこないのもどうかと考えました。 そんなわけで、今回はガチなCの話題です。

Cには昔からマクロという機能が備わっています。 マクロはプリプロセッサで前処理されて、そのあとに本格的にコンパイルされます。 プリプロセッサには否定的な意見もありますが、良くも悪くもCの特徴的な機能のひとつです。

そんなCのマクロには、関数型マクロという引数を取るものがあります。 具体的には、

#define add(a, b) ((a) + (b))

のように使います。

この引数の数を可変にできるのが可変個引数マクロです。 可変個引数マクロは次のようにして使います。

`#define eprintf(format, ...) fprintf(stderr, (format), VA_ARGS)

このマクロでは、標準エラーに書式化して出力するためのものです。 fpintfを使って素直に書いてもいいのですが、面倒ですからねえ……。

で、ここで登場する「....」の部分が可変個引数です。 可変個引数の展開する場所はVA_ARGSで指定しています。

このVA_ARGSは、マクロに渡した実引数を字面そのままに展開します。 たとえば、

eprintf("%d %d\n", 123, 456);

と書けば、

`fprintf(stderr, ("%d %d\n"), 123, 456);

のようになります。

問題ないのは、「...」の部分に引数をひとつも渡さなかった場合です。 字面通りに展開しますので、

eprintf("hello");

`fprintf(stderr, ("hello"), );

のように展開されます。

よく見ないと気付かないかもしれませんね。 最後のカンマが余計なんですよ。 これだとコンパイルエラーになってしまいます。

この問題は結構難問で、解決するのは何らかの工夫が必要になってきます。

具体的な解決方法については、次回でお話ししたいと思います。

それでは!