web-dev-qa-db-ja.com

#defineの##はどういう意味ですか?

この線はどういう意味ですか?特に、##はどういう意味ですか?

#define ANALYZE(変数、フラグ)((Something。##変数)&(フラグ))

編集:

まだ少し混乱しています。 ##がない場合、結果はどうなりますか?

33
Dante May Code

まだ少し混乱しています。 ##なしでは結果はどうなりますか?

通常、違いはわかりません。しかし、は違います違いがあります。 Somethingが次のタイプであるとします。

struct X { int x; };
X Something;

そして見てください:

int X::*p = &X::x;
ANALYZE(x, flag)
ANALYZE(*p, flag)

トークン連結演算子なし##、次のように展開されます。

#define ANALYZE(variable, flag)     ((Something.variable) & (flag))

((Something. x) & (flag))
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error!

トークンの連結により、次のように展開されます。

#define ANALYZE(variable, flag)     ((Something.##variable) & (flag))

((Something.x) & (flag))
((Something.*p) & (flag)) // .* is a newly generated token, now it works!

プリプロセッサはプリプロセッサトークンで動作し、テキストではnotであることを覚えておくことが重要です。したがって、2つのトークンを連結したい場合は、明示的にそれを言う必要があります。

17
ybungalobill

##はトークン連結と呼ばれ、マクロ呼び出しで2つのトークンを連結するために使用されます。

これを見てください:

12
Nawaz

1つの非常に重要な部分は、このトークンの連結がいくつかの非常に特別な規則に従うことです。

例えばIBMドキュメント:

  • 連結は、引数内のマクロが展開される前に行われます。
  • 連結の結果が有効なマクロ名である場合の場合、通常は使用できないコンテキストで表示されても、さらに置換することができます。
  • 1つ以上 ##演算子または#演算子、あるいはその両方がマクロ定義の置換リストにある場合、演算子の評価順序は定義されていません。

例も非常に自己説明的です

#define ArgArg(x, y)          x##y
#define ArgText(x)            x##TEXT
#define TextArg(x)            TEXT##x
#define TextText              TEXT##text
#define Jitter                1
#define bug                   2
#define Jitterbug             3

出力あり:

ArgArg(lady, bug)   "ladybug"
ArgText(con)    "conTEXT"
TextArg(book)   "TEXTbook"
TextText    "TEXTtext"
ArgArg(Jitter, bug)     3

ソースはIBMのドキュメントです。他のコンパイラによって異なる場合があります。

あなたの行へ:

変数属性を「Something」に連結します。そして、Something.variableにフラグが設定されている場合に結果を与える、論理的にANDされた変数を処理します。

だから私の最後のコメントとあなたの質問の例(g ++でコンパイル可能):

// this one fails with a compiler error
// #define ANALYZE1(variable, flag)     ((Something.##variable) & (flag))
// this one will address Something.a (struct)
#define ANALYZE2(variable, flag)     ((Something.variable) & (flag))
// this one will be Somethinga (global)
#define ANALYZE3(variable, flag)     ((Something##variable) & (flag))
#include <iostream>
using namespace std;

struct something{
int a;
};

int Somethinga = 0;

int main()
{
something Something;
Something.a = 1;

if (ANALYZE2(a,1))
    cout << "Something.a is 1" << endl;
if (!ANALYZE3(a,1))
    cout << "Somethinga is 0" << endl;
        return 1;
};
9
fyr

別の例を考えてみましょう:

検討する

#define MYMACRO(x,y) x##y

##がないと、プリプロセッサはxyを別々のトークンとして認識できません。

あなたの例では、

#define ANALYZE(variable, flag)     ((Something.##variable) & (flag))

##は、新しい識別子を作成しないため、必要ありません。実際、コンパイラーは「エラー:「。」の貼り付けを行い、「変数」は有効な前処理トークンを与えません。」

3
Chethan

これはあなたの質問に対する答えではなく、自分でプリプロセッサを探索するのに役立ついくつかのヒントを含むCWの投稿です。

前処理ステップは、実際のコードがコンパイルされる前に実際に実行されます。言い換えると、コンパイラがコードの構築を開始したときに、#defineステートメントなどは残りません。

プリプロセッサーがコードに対して何を行うかを理解する良い方法は、前処理された出力を取得してそれを確認することです。

これはWindowsでの実行方法です:

test.cppという名前のシンプルなファイルを作成し、c:\ tempなどのフォルダーに配置します。鉱山は次のようになります。

#define dog_suffix( variable_name ) variable_name##dog

int main()
{
  int dog_suffix( my_int ) = 0;
  char dog_suffix( my_char ) = 'a';

  return 0;
}

あまり便利ではありませんが、シンプルです。 Visual Studioコマンドプロンプトを開き、フォルダーに移動して、次のコマンドラインを実行します。

c:\temp>cl test.cpp /P

つまり、ファイルを使用して実行しているコンパイラ(cl.exe)であり、/ Pオプションは、前処理された出力をファイルに保存するようにコンパイラに指示します。

Test.cppの横のフォルダーにtest.iが見つかります。これは私にとっては次のようになります。

#line 1 "test.cpp"


int main()
{
  int my_intdog = 0;
  char my_chardog = 'a';

  return 0;
}

ご覧のとおり、#defineは残っていません。展開されたコードのみです。

3
sharkin

ウィキペディアによると

トークンの連結はトークンの貼り付けとも呼ばれ、Cマクロプリプロセッサの最も微妙な機能の1つであり、悪用も簡単です。 ##プリプロセッサ演算子を使用して、2つの引数を「結合」できます。これにより、2つのトークンを前処理済みコードに連結できます。これは、C++テンプレートの大まかなバージョンのように機能する複雑なマクロを構築するために使用できます。

チェック トークン連結

3
Balanivash