C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

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 );
}

結論

  • C++03 (C89) --> 「未定義」(もし意図通り動作するとすればそれはコンパイラーの独自拡張)
  • C++11 (C99) --> 「合法」(次節の「論拠」を参照)
  • C++14 (C99) --> 「合法」( C++11 を踏襲 )
  • C++17 (C11) --> 「合法」( C99 -> C11 で関連仕様は引っくり返っていない)

(Note: C++17 が C11 か C99 かで2回記事を修正しました。詳しくは記事末尾の「修正にあたり頂いた情報源」をどうぞ😃)

論拠

  1. C++11 は C99 を、C++17 は C11 を基本的には内包している。
  2. C99 規格
    1. WG14/N1256 Committee Draft - September 7, 2007 ISO/IEC 9899:TC3 §6.10.3/4
    2. Rationale for International Standard - Programming Languages - C Revision 5.10 April-2003 §6.10.3
  3. C11 規格
    1. ISO/IEC 9899:201x Committee Draft - April 12, 2011/N1570 §6.10.3/4

(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プリプロセッサーマクロでは、プリプロセッサーのトークンとしては空っぽの引数もあっていい」と書いてありました😃

参考

修正にあたり頂いた情報源

参照情報についてご意見頂き記事を再々修正しました(1回目:C++17がC11ではなくC99ままになったかと誤解して一旦断言を保留。2回目:以下のご意見からC++17はC11を参照と確認できたため記事を初稿同様C++17をC11参照として断言へ)。ありがとうございます😃