C++: C プリプロセッサーで定義されるマクロに空のパラメーターを渡す合法性
背景
ソースコード中に大量の少し複雑なアクセサー大量に定義する必要があり、久しぶりに C プリプロセッサーのマクロでアートする機会がありました。マクロを組み上げる上で1つ気になる事が生じました。「マクロに空のパラメーターを渡すのは合法か?」と。
例
#include <cstdio> #define X(X0,X1,X2) X0 ## _ ## X1 ## X2 () void Hoge_FugaPiyo() { puts( "A" ); } void Hoge_Piyo() { puts( "B" ); } int main() { X( Hoge, Fuga, Piyo ); X( Hoge, , Piyo ); }
- GCC-7.2.0
-std=c++1z -pedantic_errors
https://wandbox.org/permlink/lKAR7hpIiCHwjM6w - GCC-7.2.0
-std=c++03 -pedantic_errors
https://wandbox.org/permlink/potzF17rOIEBtkCW
結論
- C++03 (C89) --> 「未定義」(もし意図通り動作するとすればそれはコンパイラーの独自拡張)
- C++11 (C99) --> 「合法」(次節の「論拠」を参照)
- C++14 (C99) --> 「合法」( C++11 を踏襲 )
- C++17 (C11) --> 「合法」( C99 -> C11 で関連仕様は引っくり返っていない)
(Note: C++17 が C11 か C99 かで2回記事を修正しました。詳しくは記事末尾の「修正にあたり頂いた情報源」をどうぞ😃)
論拠
(2.1.) WG14/N1256 Committee Draft - September 7, 2007 ISO/IEC 9899:TC3 §6.10.3/4:
A new feature of C99: Function-like macro invocations may also now have empty arguments, that is, an argument may consist of no preprocessing tokens."
「C99における新機能: 関数様のマクロの実行において空の引数は有り得る、つまり、引数にはプリプロセッサーのトークンが無い事は有り得る。」
(2.2.) Rationale for International Standard - Programming Languages - C Revision 5.10 April-2003 §6.10.3
If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal the number of parameters in the macro definition.
「マクロ定義の識別子リストが省略記号 ( ...
) で終わっていない場合、関数様のマクロ実行の引数群(プリプロセッシングトークンが無い引数も含め)はマクロ定義と同数でなければならない。」
(3.1.) ISO/IEC 9899:201x Committee Draft - April 12, 2011/N1570 §6.10.3/4
C99 と同じ。
と、いうわけで「C++11以降のCプリプロセッサーマクロでは、プリプロセッサーのトークンとしては空っぽの引数もあっていい」と書いてありました😃
参考
- Rationale for International Standard - Programming Languages - C Revision 5.10 April-2003
- WG14/N1256 Committee Draft - September 7, 2007 ISO/IEC 9899:TC3
- ISO/IEC 9899:201x Committee Draft - April 12, 2011/N1570
- c++ - Are empty macro arguments legal in C++11? - Stack Overflow
修正にあたり頂いた情報源
参照情報についてご意見頂き記事を再々修正しました(1回目:C++17がC11ではなくC99ままになったかと誤解して一旦断言を保留。2回目:以下のご意見からC++17はC11を参照と確認できたため記事を初稿同様C++17をC11参照として断言へ)。ありがとうございます😃
C++17 から C11 参照、で合ってますよ。
— Kazutoshi SATODA (@k_satoda) 2017年11月12日
[intro.refs] (1.3) "ISO/IEC 9899:2011, Programming languages — C"https://t.co/8MkQs7kEp5