6

REQUIREアサーションを実行するためにマクロに依存する単体テスト フレームワークを使用しています。

簡略化すると、マクロは次のように機能します。

#define REQUIRE( expr ) INTERNAL_REQUIRE( expr, "REQUIRE" )

これは次のように定義されています。

#define INTERNAL_REQUIRE( expr, macroName ) \
PerformAssertion( macroName, #expr, expr );

PerformAssertionの最初の 2 つのパラメーターの型はconst char*. 2 番目のパラメーター ( ) の理由は、#exprアサートされた正確な式をログに記録できるようにするためです。ここに問題があります。プリプロセッサは、 として渡される前に式を展開するconst char *ため、最初にアサートされた式と同じではありません。

例えば:

REQUIRE( foo != NULL );

この呼び出しは次のようになります。

PerformAssertion( "REQUIRE", "foo != 0", foo != 0 );

ご覧のとおり、式は部分的に展開されています。たとえば、式foo != NULLはログに として表示されますfoo != 0。(NULLと定義されたマクロ0) は、アサーション メッセージ テキストを作成する前に、C プリプロセッサによって展開されました。メッセージ テキストの展開を無視またはバイパスする方法はありますか?

編集:好奇心旺盛な人のための解決策は次のとおりです。

#define REQUIRE( expr ) INTERNAL_REQUIRE( expr, #expr, "REQUIRE" )

#define INTERNAL_REQUIRE( expr, exprString, macroName ) \
PerformAssertion( macroName, exprString, expr );
4

2 に答える 2

5

内部requireを呼び出す前に、文字列化を行ってみてください。あなたの問題は、それがNULLを展開する2番目の展開で内部requireに渡されることです。その前に文字列化を実行すると、たとえば、requireマクロでは、NULLは展開されません。

于 2012-06-19T17:23:13.917 に答える
2

ここで何が起こっているか: 「文字列化」演算子#が適用されるマクロは第 2 レベルであるため、一連の操作は次のように機能します。

  • プリプロセッサは引数を識別し、C 6.10.3.1 に従って引数置換REQUIRE(NULL)を実行します。この時点で、は として展開されるため、置換は のようになります。INTERNAL_REQUIRE( 0, "REQUIRE" )NULL0
  • プリプロセッサはINTERNAL_REQUIRE;でマクロ チェーンを展開し続けます。この時点で、マクロが で呼び出されたという事実NULLは失われます: プリプロセッサに関する限り、 に渡される式INTERNAL_REQUIREは です0

この問題を解決する鍵は、標準の次の段落にあります。

# または ## 前処理トークンが先行するか、## 前処理トークンが後続しない限り (以下を参照)、置換リスト内のパラメーターは、そこに含まれるすべてのマクロが展開された後に、対応する引数に置き換えられます。

これは、正確な式をキャプチャしたい場合は、マクロ展開の最初のレベルで行う必要があることを意味します。

于 2012-06-19T17:45:47.847 に答える