7

連結によって形成された多くの定数文字列(数字など)があるプロジェクトに取り組んでいます。

たとえば、メッセージやエラーを出力するときに、コード内のどこにいるかを知るために使用できる文字列にLOCATIONフォーマットするマクロが__FILE__あります。__LINE__

#define _STR(x)    # x
#define STR(x)     _STR(x)
#define LOCATION __FILE__ "(" STR(__LINE__) ")"

したがって、これは「file.cpp(42)」のような場所をフォーマットします。問題は、結果をワイド文字列に変換しようとしたときです。

#define _WIDEN(x)  L ## x
#define WIDEN(x)   _WIDEN(x)
#define WLOCATION  WIDEN(LOCATION)

これは GCC で問題なく動作し、L"file.cpp(42)" がコードに挿入されます。ただし、MSVC++ (Visual C++ 2008 Express を使用) でこれを試みると、エラーが発生します。

error: Concatenating wide "file.cpp" with narrow "("

Lプレフィックスが式の最初の項にのみ追加されることを理解しています。私もこれを試しました:

#define _WIDEN(x) L ## #x

これは「機能します」がL"\"file.cpp\" \"(\" \"42\" \")\""、特にこのマクロが他のマクロと比較して単純であることを考えると、明らかにあまり便利ではない (そして私が探しているものではない) 文字列を提供します。

それで、私の質問は次のとおりです。MSVC ++の式全体に適用するにはどうすればよいので、GCCで得ているのと同じ結果を得ることができますか? 全幅のトークンを含む 2 番目の文字列を作成したくはありません。これは、マクロごとに 2 つのマクロを維持する必要があり、あまり便利ではなく、バグにつながる可能性があるためです。さらに、各文字列の狭いバージョンも必要なので、残念ながらすべて広い文字列を使用することもできません。

4

3 に答える 3

12

C標準(別名「ISO-9899:1999」、別名「C99」)によると、Visual Cは間違っており、gccは正しいです。その標準は、セクション6.4.5/4に述べています。

変換フェーズ6では、隣接する文字の任意のシーケンスとワイド文字列リテラルトークンによって指定されたマルチバイト文字シーケンスが、単一のマルチバイト文字シーケンスに連結されます。トークンのいずれかがワイド文字列リテラルトークンである場合、結果のマルチバイト文字シーケンスはワイド文字列リテラルとして扱われます。それ以外の場合は、文字列リテラルとして扱われます。

だからあなたは苦情を申し立てることができます。間違いなく、以前のバージョンのC標準(別名「C89」、別名「C90」、別名「ANSI C」)では、幅の広い文字列と幅のない文字列のマージは義務付けられていませんでした。C99は現在10年以上前のものですが、MicrosoftはCコンパイラを準拠させることに関心がないようです。一部のユーザーは、C ++にこれらの機能が含まれているため、CコードをC ++コードであるかのようにコンパイルすることで、一部の「C99」機能にアクセスできると報告しています。C++については、Microsoftが努力しました。しかし、これはプリプロセッサには及ばないようです。

C89方言では、あなたが探しているものは不可能だと思います(実際、私はそれをかなり確信しています。私は自分のプリプロセッサを書いたので、私が話していることを知っていると思います)。ただし、パラメータを追加して伝播することもできます。

#define W(x)          W_(x)
#define W_(x)         L ## x
#define N(x)          x
#define STR(x, t)     STR_(x, t)
#define STR_(x, t)    t(#x)

#define LOCATION_(t)  t(__FILE__) t("(") STR(__LINE__, t) t(")")
#define LOCATION      LOCATION_(N)
#define WLOCATION     LOCATION_(W)

これはgccとVisualCの両方で動作するはずです(少なくとも、Visual C 2005を使用すると動作します)。

補足:アンダースコアで始まる名前でマクロを定義しないでください。これらの名前は予約されているため、これらを使用すると、システムヘッダーまたはコンパイラの将来のバージョンで使用されるいくつかの名前と衝突する可能性があります。の代わりに_WIDEN、を使用しますWIDEN_

于 2010-02-03T15:08:01.813 に答える
1

使用できる2つのワイドリテラル文字列を連結するには

L"wide_a" L"wide_b"

だからあなたは定義することができます

#define WLOCATION WIDEN(__FILE__) L"(" WIDEN(STR(__LINE__)) L")"

(注: MSVC++ ではテストされていません)

于 2010-02-03T14:09:28.920 に答える