3

逆参照演算子を使用したプリプロセッサの貼り付けの「##」について質問があります。以下のコードがコンパイルされない理由を誰か教えてもらえますか?

typedef struct
{
    char data;
} MY_STRUCT;

MY_STRUCT  My_Instance;
MY_STRUCT* My_PInstance;

#if 1
#define GET_MEMBER(membername)         (My_PInstance->##membername)
#else
#define GET_MEMBER(membername)         (My_Instance.##membername)
#endif

その後、私が電話したとき:

char value = GET_MEMBER(data);  // Where My_PInstance is properly instantiated.

コンパイルエラーが発生します。

error: pasting "->" and "data" does not give a valid preprocessing token
4

2 に答える 2

6

貼り付ける必要はありません。やるだけ(My_Pinstance->membername)

「##」は、2 つのトークンを 1 つの有効なトークンに貼り付ける必要があります。ただし ->foo、有効なトークンではありません。(fooは例です)

于 2012-12-05T02:39:08.837 に答える
2

ここに来る他の誰かのためだけに。私は同じ問題を抱えていましたが、「。」議論されていない GET_MEMBER(..) マクロの変種ですが、問題は同じだと思います。

本当に貼り付けられていたのはテキストだったので、cwyangの答えをためらって受け入れました

My_PInstance->

data

-- 私 (およびユーザー...) の考えによると、結果は適切なトークンです。

My_PInstance->data

それで、私はより多くのグーグルの結果を固執しました。最終的に、私はこの男にたどり着きました。この男は、本当に打撃を受けた歴史的なメモを残しています。概要:

昔に戻ると、古い代替構文が存在しましたが、コンパイラはもはやそのナンセンスを認識していません。そこにも行かないでください。

おとこ。こいつは希望がないと言っている……。

さて、一体何?私はそこに行きました。代替構文は機能し、古いコンパイラはほとんど使用していません!

g++ (GCC) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.

ですから、勇敢な文字列指定子、連結子、トークナイザー (!) の皆さんに、ここで私の教訓をお伝えします。

前:

#define PROFILING_START_CLK(STAT, n)                        \
    time0##STAT##n = PRF_CLK_FN();                          \
    profilingStatsIndex##STAT##n = STAT##.count % PROFILE_SIZE; \
    STAT#.count++;

このように呼ばれます:

PROFILING_START_CLK(tst, 0);

使用された場所ごとに、次のエラーの 2 つのインスタンスを返します。

error: pasting "tst" and "." does not give a valid preprocessing token

user1159503のように。

ただし、先に進みます.... 次のように動作します:

#define PROFILING_START_CLK(STAT, n)                          \
    time0##STAT##n = PRF_CLK_FN();                            \
    profilingStatsIndex##STAT##n = STAT/**/.count % PROFILE_SIZE;\
---------------------------------------^^^^
    STAT/**/.count++;
--------^^^^

g++ -ansi スイッチを使用したかどうかに関係なく、前/後のバージョンは失敗/コンパイルされました。

これが機能する理由は、プリプロセッサがマクロに入る前にコメントを削除するためで、順序は次のようになります。

  1. 「/**/」が削除されると、STAT が .count に隣接します。
  2. 「##」プロセスは回避されます。特に、有効な結果トークンのチェックは、コードのこの時点で回避されます。
  3. STATは「tst」に文字列化されます(私の場合)
  4. 後続の解析/トークン チェックでは、「tst.count」が適切で適切であることがわかります。

'##' は、マクロ内の任意の構造体および/またはメンバーをアセンブルするために機能する必要がありますか? 知らない。私はそう思いますが、貼り付けプロセスがオペレーターにまたがらないことも正しいようです。

それ以外の場合、「ここで話しているように、貼り付けプロセスが「結合」演算子のみにまたがるのは合理的ですか。('.'、'->'、'::'、....)」という疑問が生じます。

于 2013-10-18T19:03:57.557 に答える