1. ホーム
  2. c

[解決済み] GCCの##__VA_ARGS__トリックの標準的な代替手段?

2022-04-26 16:50:50

質問

があります。 よく知られている 問題 C99で可変長マクロの引数が空だったこと。

の例です。

#define FOO(...)       printf(__VA_ARGS__)
#define BAR(fmt, ...)  printf(fmt, __VA_ARGS__)

FOO("this works fine");
BAR("this breaks!");

の使用は BAR() に展開されるため、C99規格によれば確かに不正確である。

printf("this breaks!",);

最後のコンマに注意 - 実行不可能です。

いくつかのコンパイラ(例:Visual Studio 2010)は、この末尾のカンマを静かに取り除いてくれます。他のコンパイラ(例:GCC)は ## の前にある __VA_ARGS__ というように。

#define BAR(fmt, ...)  printf(fmt, ##__VA_ARGS__)

しかし、この動作を得るための標準に準拠した方法はあるのでしょうか? もしかしたら、複数のマクロを使うとか?

今現在は ## のバージョンは、(少なくとも私のプラットフォームでは)かなりよくサポートされているようですが、私はむしろ標準に準拠したソリューションを使いたいと思っています。

先取りです。小さな関数を書けばいいのは分かっているのですが。マクロを使ってやってみたいんです。

編集 : BAR()を使いたくなるような例を(簡単ですが)挙げておきます。

#define BAR(fmt, ...)  printf(fmt "\n", ##__VA_ARGS__)

BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);

これは、BAR() のロギングステートメントに自動的に改行を追加し、次のように仮定します。 fmt は常にダブルクォートされたC文字列である。これは、改行を別の printf() として表示しません。これは、ロギングがラインバッファリングされ、複数のソースから非同期に送られてくる場合に有利です。

解決するには?

GCC の ,##__VA_ARGS__ で説明されているように、可変個数マクロに渡すことができる引数の数にハードコードされた上限を受け入れることができるのであれば、拡張機能を使用することができます。 この質問に対するリチャード・ハンセン氏の回答 . clangとiccはこのGCC拡張を採用していますが、MSVCは採用していません。

2001年に私は標準化のためのGCC拡張機能(および関連する拡張機能で __VA_ARGS__ にあるように、残りのパラメータは ドキュメントN976 しかし、委員会からは何の反応もなく、誰かが読んだかどうかもわからない。 2016年に再び提案されたのは N2023 その提案がどうなっているのかご存知の方は、ぜひコメントで教えてください。