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

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

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

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

この話題もいよいよ最終回になりました。 これまで、Cの可変個引数マクロについて見てきましたが、普通は前回と前々回の方法で何とかなると思います。

今回はちょっと特殊な扱い方をご紹介します。 トリッキーだと思われる方もいらっしゃるのではないでしょうか?

それでは行ってみましょう!

複合リテラルを使う

Cの標準規格に可変個引数が導入されたのはC99からです。 そのC99では、ほかに複合リテラルという機能も導入されました。 今回はそれを使う方法をご紹介します。

#define macro(arg1, ...) \
        func((arg1), sizeof((int[]){ 0, __VA_ARGS__ })/sizeof(int), (int[]){ 0, __VA_ARGS__ })

こうやってみるとかなり複雑になってしまいましたね。

やっていることは大して難しくありません。 複合リテラルが2回登場しますが、どちらも次の形式になっています。

(int[]){ 0, __VA_ARGS__}

複合リテラルの先頭要素に0を入れていますので、可変個引数がひとつもなくても最初の0が必ず入ります。 また、配列の初期化子では、最後の要素にもカンマがあっても問題ありません。 要素数が実際より1個増えてしまうので、その点だけは要注意です。

マクロに登場する1回目の複合リテラルでは、配列の要素数を数えています。 こうすることで、可変個引数の数を調べることができます。

2回目の複合リテラルは、func関数に値を渡すために使っています。 こうすることで、可変個引数の値も個数もfunc関数に渡すことができます。

可変個引数がひとつもない場合の話題からはそれますが、複合リテラルを配列ではなく構造体にすれば、いろいろな型の引数を渡すことができます。 構造体の場合には、指示付き初期化子を利用すれば、Rubyのキーワード引数のようなこともできますね。

Cは工夫次第でいろいろな方法を編み出すことができる楽しい言語だと思っています。 ちょっと難解な方法を使おうとすると嫌がられる職場もあるようですが、それはそれとして、いろいろな可能性を日ごろから探ることは悪くないと思いますよ!

というわけで、これでマクロの可変個引数に関する話題はいったん終わりにします。

それでは!!!