C ++のwchar_tとwstringsの「間違った」とは何ですか?ワイド文字に代わるものは何ですか?


86

C ++コミュニティ(特にfreenodeの## c ++)の多くの人々が、wstringsとの使用、およびWindowsAPIwchar_tでのそれらの使用に憤慨しているのを見てきました。まったく「間違っている」とは何であるwchar_twstring、私は国際化をサポートしたい場合は、ワイド文字にはいくつかの選択肢は何ですか?


1
そのための参照がありますか?
ダニ

14
おそらく、この素晴らしいスレッドはあなたのすべての質問に答えますか?stackoverflow.com/questions/402283/stdwstring-vs-stdstring
MrFox 2012年

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

12
utf8everywhere.orgには、ワイド文字を避ける理由についての適切な議論があります。
JoeG 2012年

5
@jamesdlin確かにあなたには選択肢があります。nowideライブラリは、APIに渡すときに文字列を変換する便利な方法を提供します。文字列を使用したAPI呼び出しは通常低頻度であるため、アドホックを変換し、ファイルと内部変数を常にUTF-8に含めるのが妥当な方法です。
Pavel Radzivilovsky 2012年

回答:


114

wchar_tとは何ですか?

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

タイプ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プラットフォームでは定義されていますが、Windowsがすべてのロケールで同じwchar_tロケールを使用していても、Windowsはそれを定義しないため、この方法でwchar_tを使用できるかどうかを判断するのにそれだけに頼ることはできません。

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

プラットフォーム固有のコードの場合、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を使用)。

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

一部のソフトウェアで使用されるもう1つの方法は、UTF-16データを保持する符号なしの短い配列などのクロスプラットフォーム表現を選択し、すべてのライブラリサポートを提供し、言語サポートなどのコストを負担することです。

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

避けるべき代替案

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


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

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


3
追加:utf8everywhere.orgはWindowsでUTF-8を使用することを推奨しており、Boost.Nowideは正式なレビューが予定されています。
ヤコフガルカ2012年

2
もちろん、最良の方法は、WindowsでC#またはVB.Netを使用することです:)または単純な古いC / Win32。ただし、C ++を使用する必要がある場合は、TCHARが最適な方法です。MSVS2005以降ではデフォルトで「wchar_t」になります。私見...
paulsm4

4
@BrendanMcK:確かに、WindowsではWin32 APIを使用し、他のシステムでは他のAPIを使用するコードは存在しません。正しい?マイクロソフトのアプローチ(「アプリのあらゆる場所で内部的にwcharを使用する」)の問題は、システムに直接インターフェイスせず、移植可能である可能性のあるコードにも影響を与えることです。
Yakov Galka 2012年

4
問題は、ANSIコードページとしてUTF-8をサポートしないというMicrosoftの決定が、標準C(++)ライブラリを「壊す」ため、Windows固有の関数を使用する必要あることです。たとえばfopen、名前にANSI以外の文字が含まれているファイルを作成することはできません。
dan04 2012年

11
@ dan04はい、Windowsで標準ライブラリを使用することはできませんが、Win32 W関数を使用する前に、他のプラットフォームで標準ライブラリをラップし、UTF-8からwchar_tに直接変換するポータブルインターフェイスを作成できます。
bames53 2012年

20

wchar_tには「間違った」ものは何もありません。問題は、NT 3.xの時代に、MicrosoftがUnicodeが適切であると判断し(現在)、Unicodeを16ビットのwchar_t文字として実装することです。したがって、90年代半ばのほとんどのMicrosoftの文献は、Unicode == utf16 == wchar_tとほぼ同等でした。

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

これは、私が今まで見た「Unicode」(この質問とは無関係、C ++とは無関係)の最高の入門書の1つです。私はそれを強くお勧めします:

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

私見では...

PS:

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.