87

C++ コミュニティ (特に freenode の ##c++) の多くの人々が、 と の使用、および Windows API での使用に憤慨しているのを見てきwstringsましwchar_tた。wchar_tandで正確に「間違っている」のは何wstringですか?国際化をサポートしたい場合、ワイド文字に代わるものは何ですか?

4

2 に答える 2

115

wchar_t とは何ですか?

wchar_t は、すべての wchar_t が正確に 1 つのコードポイントを表す wchar_t 表現に任意のロケールの char エンコーディングを変換できるように定義されています。

型 wchar_t は、サポートされているロケール (22.3.1) で指定された最大の拡張文字セットのすべてのメンバーの個別のコードを値で表すことができる個別の型です。

                                                                               — C++ [basic.fundamental] 3.9.1/5

これは、wchar_t がすべてのロケールの任意の文字を同時に表すのに十分な大きさである必要はありません。つまり、wchar_t に使用されるエンコーディングは、ロケールによって異なる場合があります。つまり、あるロケールを使用して文字列を wchar_t に変換してから、別のロケールを使用して char に戻すとは限りません。1

すべてのロケール間で共通の表現として wchar_t を使用することは、実際には wchar_t の主な用途であるように思われるため、そうでない場合は何に役立つのか疑問に思うかもしれません。

wchar_t の当初の意図と目的は、文字列のコード単位からテキストの文字への 1 対 1 のマッピングを必要とするように定義することで、テキスト処理を単純にすることでした。これにより、使用されているのと同じ単純なアルゴリズムを使用できるようになります。 ASCII 文字列を使用して、他の言語で動作します。

残念ながら、wchar_t の仕様の文言は、これを実現するために文字とコードポイント間の 1 対 1 のマッピングを前提としています。Unicode はその仮定2を破るため、単純なテキスト アルゴリズムにも wchar_t を安全に使用することはできません。

これは、移植可能なソフトウェアが、ロケール間のテキストの共通表現として、または単純なテキスト アルゴリズムの使用を可能にするために、wchar_t を使用できないことを意味します。

今日の wchar_t は何に使用されますか?

とにかく、移植可能なコードの場合はそれほど多くありません。が定義されている場合__STDC_ISO_10646__、wchar_t の値は、すべてのロケールで同じ値を持つ Unicode コードポイントを直接表します。これにより、前述のロケール間の変換を安全に行うことができます。ただし、ほとんどの UNIX プラットフォームで wchar_t を定義しているのに対し、Windows はすべてのロケールで同じ wchar_t ロケールを使用しているにもかかわらず、Windows では定義していないため、この方法で wchar_t を使用できるかどうかを判断するために、それだけに依存することはできません。

Windows が定義しない理由__STDC_ISO_10646__は、Windows がその wchar_t エンコーディングとして UTF-16 を使用し、UTF-16 がサロゲート ペアを使用して U+FFFF より大きいコードポイントを表すためです。これは、UTF-16 が の要件を満たさないことを意味します__STDC_ISO_10646__

プラットフォーム固有のコードでは、wchar_t の方が便利な場合があります。これは、Windows では基本的に必要です (たとえば、一部のファイルは、wchar_t ファイル名を使用せずに開くことができません) が、私が知る限り、Windows はこれが当てはまる唯一のプラットフォームです (したがって、wchar_t を 'Windows_char_t' と考えることができます)。

後から考えると、wchar_t はテキスト処理の簡素化や、ロケールに依存しないテキストのストレージとしては明らかに役に立ちません。移植可能なコードは、これらの目的で使用しないでください。一部の API がそれを必要とするという理由だけで、移植性のないコードが役立つ場合があります。

代替案

私が気に入っている別の方法は、UTF-8 にあまり適していないプラットフォームでも、UTF-8 でエンコードされた C 文字列を使用することです。

このようにして、プラットフォーム間で共通のテキスト表現を使用して移植可能なコードを記述し、意図した目的のために標準のデータ型を使用し、それらの型に対する言語のサポートを得ることができます (例: 文字列リテラル。一部のコンパイラで機能させるにはいくつかのトリックが必要です)。標準ライブラリのサポート、デバッガーのサポート (より多くのトリックが必要になる場合があります) など。ワイド文字では、これらすべてを取得することは一般に困難または不可能であり、異なるプラットフォームでは異なる部分を取得する可能性があります。

UTF-8 が提供しないことの 1 つは、ASCII で可能なような単純なテキスト アルゴリズムを使用する機能です。この UTF-8 は、他の Unicode エンコーディングよりも悪くありません。実際、UTF-8 でのマルチコード単位表現がより一般的であり、そのような文字の可変幅表現を処理するコードのバグは、UTF に固執しようとする場合よりも気づき、修正される可能性が高いため、より良いと見なされる場合があります。 -32 NFC または NFKC を使用。

多くのプラットフォームは、ネイティブの char エンコーディングとして UTF-8 を使用し、多くのプログラムは重要なテキスト処理を必要としないため、これらのプラットフォームで国際化されたプログラムを作成することは、国際化を考慮せずにコードを作成することとほとんど変わりません。移植性の高いコードを作成したり、他のプラットフォームで作成したりするには、他のエンコーディングを使用する API の境界に変換を挿入する必要があります。

一部のソフトウェアで使用される別の代替手段は、UTF-16 データを保持する符号なしの短い配列などのクロスプラットフォーム表現を選択し、すべてのライブラリ サポートを提供して、言語サポートなどのコストを単純に受け入れることです。

C++11 では、wchar_t、char16_t、および char32_t の代替として、付随する言語/ライブラリ機能を備えた新しい種類のワイド文字が追加されています。これらは実際には UTF-16 および UTF-32 であることが保証されているわけではありませんが、主要な実装で他のものを使用することはないと思います。u8C++11 では、UTF-8 文字列リテラルなどの UTF-8 サポートも改善されているため、VC++ をだまして UTF-8 でエンコードされた文字列を生成させる必要はありません (ただし、プレフィックスを使用するのではなく、引き続きそうする可能性があります)。 .

避けるべき代替手段

TCHAR: TCHAR は、従来のエンコーディングを char から wchar_t に想定する古代の Windows プログラムを移行するためのものであり、プログラムが何千年も前に作成されていない限り、忘れるのが最善です。移植性がなく、エンコーディングやデータ型についても本質的に不特定であるため、TCHAR ベース以外の API では使用できません。その目的は上で見た wchar_t への移行であるため、これは良い考えではありません。TCHAR を使用しても何の価値もありません。


1. wchar_t 文字列で表現できるが、どのロケールでもサポートされていない文字は、単一の wchar_t 値で表現する必要はありません。これは、wchar_t が特定の文字に対して可変幅エンコーディングを使用できることを意味します。これは、wchar_t の意図に対するもう 1 つの明らかな違反です。文字が wchar_t で表現可能であるということは、ロケールがその文字を「サポートする」と言うのに十分であるという議論の余地がありますが、その場合、可変幅エンコーディングは合法ではなく、Windows の UTF-16 の使用は非準拠です。

2. Unicode では、多くの文字を複数のコード ポイントで表すことができます。これにより、単純なテキスト アルゴリズムに対して可変幅エンコーディングと同じ問題が生じます。構成された正規化を厳密に維持したとしても、一部の文字には複数のコード ポイントが必要です。参照: http://www.unicode.org/standard/where/

于 2012-06-19T19:05:30.863 に答える
21

wchar_t には「問題」はありません。問題は、NT 3.x の時代に、Microsoft が Unicode は良いものである (実際にそうである) と判断し、Unicode を 16 ビットの wchar_t 文字として実装することを決定したことです。そのため、90 年代半ばのほとんどのマイクロソフトの文献では、Unicode == utf16 == wchar_t とほぼ同一視されていました。

悲しいことに、これはまったく当てはまりません。「ワイド文字」は、すべてのプラットフォームで、すべての状況下で必ずしも 2 バイトであるとは限りません。

これは、私が今まで見た「Unicode」に関する最高の入門書の 1 つです (この質問とは関係なく、C++ とは関係ありません):強くお勧めします:

そして、「8ビットASCII」対「Win32ワイド文字」対「wchar_t-in-general」を処理する最善の方法は、単に「Windowsは異なる」ことを受け入れ、それに応じてコーディングすることだと正直に信じています。

私見では...

PS:

上記のjamesdlinに完全に同意します:

Windows では、実際には選択肢がありません。その内部 API は UCS-2 用に設計されました。これは、可変長の UTF-8 および UTF-16 エンコーディングが標準化される前であったため、当時は合理的でした。しかし、UTF-16 をサポートするようになった今、両方の世界で最悪の結果になりました。

于 2012-06-25T21:52:32.737 に答える