マクロの違い## Visual-C ++とgccの連結演算子
-
05-07-2019 - |
質問
このようなマクロを持っています(正確ではありませんが、機能はまったく同じです):
#define STRUCTMEMBER(Member,Value) GlobalStructInstance. ## Member = Value
...
STRUCTMEMBER(Item,1);
これはVisual C ++では完全に機能しますが、gcc 3.4.5(MingGW)では次のエラーが発生します。
貼り付け"。"および「アイテム」有効な前処理トークンを与えません
これは、"->"を使用したときにも発生します。オペレーター。これらの演算子の使用は禁止されているという連結に関するヒントは見つかりませんでした。
誰にもアイデアはありますか?
解決
おそらく、Visual C ++はいくつかのスペースを貼り付けて別のスペースを作成しています。空白はトークンではありませんが、コードを機能させることができます。
object.member
はトークンではなく、3つのトークンであるため、説明するマクロを実装するためにトークンを貼り付ける必要はありません。 「##」を削除するだけで、どこでも機能します。
[編集:チェックしたばかりで、##を使用して有効なトークンではないものを作成した結果は未定義です。したがって、GCCはそれを拒否することが許可され、MSVはそれを無視して貼り付けを実行することを許可されています。]
他のヒント
C標準によると、「 ##
」前処理演算子の結果は「前処理トークン」である必要があります。そうでない場合、結果は未定義です(C99 6.10.3.3(3)-##演算子)。
前処理トークンのリストは(C99 6.4(3)-字句要素):
ヘッダー名、識別子、前処理番号、文字定数、文字列リテラル、句読点、および他の前処理トークンカテゴリと字句的に一致しない単一の非空白文字。
GCCを使用すると、未定義の領域に入っていることがわかります。 MSVCは、未定義の結果に静かに満足しています(これは、あなたが期待することです)。
とにかく単一のトークンを作成しない場合、トークン貼り付け演算子は必要ないことに注意してください。一般的に(おそらく1つまたは2つの例外があると思います)、空白で区切られた2つのトークンは、例のように空白で区切られていない2つのトークンと同等です。
ただし、一緒になって有効なトークンを形成しない2つのトークンを貼り付けることはできません。
structure.memberは単一のトークンではありません。
この場合、##(トークン連結)演算子を使用する必要はありません。削除するだけです。 Linuxでgcc 4.2.4を使用してテストした例を次に示します。
#include <stdio.h>
#define STRUCTMEMBER(Member, Value) GlobalStructInstance.Member = Value
struct {
const char* member1;
}GlobalStructInstance;
int main(void)
{
STRUCTMEMBER(member1, "Hello!");
printf("GlobalStructInstance.member1 = %s\n",
GlobalStructInstance.member1);
return 0;
}