web-dev-qa-db-ja.com

MSVCが__VA_ARGS__を正しく展開しない

このコードを考えてみましょう:

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)

予想される出力はX = 1 and VA_ARGS = 2, 3両方のマクロで、GCCを使用してこれを実現していますが、MSVCはこれを次のように展開します。

X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =

あれは、 __VA_ARGS__は、複数の引数に分解されるのではなく、単一の引数として展開されます。

これを回避する方法はありますか?

49
uj2

MSVCのプリプロセッサは、標準仕様とはかなり異なる動作をするようです。
おそらく、次の回避策が役立ちます。

#define EXPAND( x ) x
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) EXPAND( F(__VA_ARGS__) )
45
Ise Wisteria

私が投稿した 次のMicrosoftサポートの問題

次のプログラムでは、プリコンパイラーが__VA_ARGS__を誤って展開するため、コンパイルエラーが発生します。

#include <stdio.h>

#define A2(a1, a2) ((a1)+(a2))

#define A_VA(...) A2(__VA_ARGS__)

int main(int argc, char *argv[])
{
    printf("%d\n", A_VA(1, 2));
    return 0;
}

プリプロセッサは、printfを次のように展開します。printf( "%d\n"、((1、2)+()));

printf( "%d\n"の代わりに、((1)+(2)));

Microsoftコンパイラチームの開発者から、次の満足のいく答えを受け取りました。

こんにちは:この場合、Visual C++コンパイラーは正しく動作しています。最初のマクロ呼び出しで「...」に一致するトークンが結合されて単一のエンティティ(16.3/p12)を形成するという規則と、サブマクロが引数置換の前に展開される(16.3.1/p1)という規則を組み合わせる場合)次に、この場合、コンパイラは、A2が単一の引数で呼び出されたと見なします。したがって、エラーメッセージです。

21
dmitryvolk

どのバージョンのMSVCを使用していますか? Visual C++ 2010が必要です。

__VA_ARGS__はC99で最初に導入されました。 MSVCはC99をサポートしようとしたことがないため、サポートは追加されませんでした。

ただし、現在、__VA_ARGS__は新しいC++標準であるC++ 2011(以前はC++ 0xと呼ばれていました)に含まれています。Microsoftはこれをサポートする予定であるため、最近のバージョンのMSVCでサポートされています。

ところで、このサポートを受けるには、ソースファイルに.cppサフィックスを使用する必要があります。 MSVCはCフロントエンドを長い間更新していません。

1
chys