2016-12-02 11 views
0

のパラメータリストを生成するためにマクロを使用する方法:それらのそれぞれのためCマクロは:私は以下のようなコードの行の多くを持っている別のマクロ

 sp_setup_point(setup, get_vert(vertex_buffer, i-0, stride)); 

を、私はI-(抽出することができるようにしたいです0)、それを別の関数に渡します。以下のような:好き

 #define GET_VERT(_x, _y, _z) get_vert(_x, _y, _z) , _y 
     #define SP_SETUP_POINT(_x, _y, _z) sp_setup_point(_x, _y); my_test_func(_z); 

とそれらを呼び出す:

 SP_SETUP_POINT(setup, GET_VERT(vertex_buffer, i-0, stride)); 

しかし、それは私が望むものを与えるものではありません、それは次のように拡張されます

 sp_setup_point(setup, get_vert(vertex_buffer, i-0, stride)); 
    my_test_func(i-0); 

ので、私はマクロ2を書きました
 sp_setup_point(setup, get_vert(vertex_buffer, i-0, stride), i-0); my_test_func(); 

とMSVCコンパイラが

not enough actual parameters for macro 'SP_SETUP_POINT' 

Iは、それらがマクロ本体に代入される前に、それらが他のトークンと文字列化または貼り付けられていない限り、マクロ引数は、完全にマクロ展開さhttps://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html

によれば、かなり検索。置換後、置換された引数を含むマクロ本体全体が再度走査され、マクロが展開されます。その結果、引数が2回スキャンされ、マクロ呼び出しが展開されます。

引数は完全に展開されますが、追加の引数は認識されません。それはどうですか?任意の提案は高く評価されます。

+0

ヒント:コンパイラのオプションを使用して、前処理されたソースコードを出力して、式の評価対象を確認します。 – doynax

+0

はい、試しました。私は前処理した後にコードを手に入れましたが、望むマクロ展開を得る方法はまだ分かりません。 – luckyyang

答えて

1

理由、IIRCは、包囲マクロ呼び出しが走査さ後の実際のパラメータリストの内部GET_VERT のみ拡張されることをです。したがって、PPは最初にSP_SETUP_POINTのパラメータリストの最後に ")"を表示する必要があります。このプロセスでは、宣言されたフォームの1つのパラメータが不足していることを認識します。インダイレクションの1つのレベルは助けになりますが、C言語のマクロプログラミングは奇妙であり、互換性のない巨額の債務のために誰も修正できなかったインプリメンテーションの初期段階の悪さから苦しんでいます。 SGを書いているので、最後のフォームが良く

#define SP_SETUP_POINT_(_x,_y,_z) do{ sp_setup_point(_x, _y); my_test_func(_z); }while(0) 

として書かれ

#define GET_VERT(_x, _y, _z) get_vert(_x, _y, _z) , _y 
#define SP_SETUP_POINT(_x, expandme) SP_SETUP_POINT_(_x,expandme) 
#define SP_SETUP_POINT_(_x,_y,_z) sp_setup_point(_x, _y); my_test_func(_z) 

if (a==1) SP_SETUP_POINT(setup, GET_VERT(vertex_buffer, i-0, stride)); 

は、制御フローで目に見えないエラーにつながります。私はこれに取り組むつもりだった場合

+1

詳細なアンサーをありがとう。私もそれについて考えましたが、このように運はありません。ここに私のバージョンです: 'の#define SP_SETUP_POINT(...)SP_SETUP_POINT_IMPL(__ VA_ARGS __)' 'の#define SP_SETUP_POINT_IMPL(_x、_y、_Z)sp_setup_point(_x、_y)は、 \t my_test_func(_z) ' – luckyyang

1

、私は私が所望の出力から始めると思う:

sp_setup_point(setup, get_vert(vertex_buffer, i-0, stride)); 
my_test_func(i-0); 

あなたは4つのパラメータがあります:expri-0パラメータでありsetupvertex_bufferexpr、およびstrideを、 (これはそれ自体特有の記法であり、それはiとどのように異なるのでしょうか?)私は、プロダクション品質のマクロで長い名前を使うかもしれません。私は短い名前を使用するつもりですa ..dはこちら。

だから、私はその出発点からの私のマクロを設計したい:あなたはそれから呼び出すことができ

#define SP_SETUP_POINT(a, b, c, d) \ 
    do { sp_setup_point((a), get_vert((b), (c), (d))); \ 
     my_test_func(c); } while (0) 

SP_SETUP_POINT(setup, vertex_buffer, i-0, stride); 

をこれでもこのような状況では、あなたが望むコードを生成します:

if (x > y) 
    SP_SETUP_POINT(setup, vertex_buffer, i-0, stride); 
else 
    SP_SETUP_POINT(setup, vertex_buffer, i+2, stride); 

あなたがdo { … } while (0)表記を使用しない場合、あなたはコンマオペアンプを使用する必要があります機能を分離するeratorコール:

#define SP_SETUP_POINT(a, b, c, d) \ 
    (sp_setup_point((a), get_vert((b), (c), (d))), \ 
    my_test_func(c)) 

これはmy_test_func()からの戻り値を評価します。戻り値をsp_setup_point()からテストする必要がない場合は問題ありません。とにかくvoidを返した場合、my_test_func()voidを返す場合は問題ありません。

ます。また、その後 MY_TEST_FUNC(c)を呼び出すためにマクロを変更することができ

は条件付きでそれを定義:

#ifdef CALL_MY_TEST_FUNCTION 
#define MY_TEST_FUNC(c) my_test_func(c) 
#else 
#define MY_TEST_FUNC(c) ((void)(c)) 
#endif 

「と呼ぶいない」場合cを評価することの利点は、コンパイラがcがさえとして有効であり続けることを保証していることですコードが変更されます。長寿命のコードでは、そのメリットを過小評価しないでください。

+1

別の観点から感謝します。もし私がマクロのミステリーを理解できなければ。私はこの方法を採用します。元のコードの多くの侵略的な変更が必要なので、私はそれを最善の解決策として取っていません。 – luckyyang

関連する問題