1. ホーム
  2. c++

[解決済み] C++のwchar_tとwstringsの何が "悪い "のですか?ワイド文字の代用品は何ですか?

2023-05-09 20:49:04

質問

C++ コミュニティ (特に freenode の ##c++) で、多くの人が wstringswchar_t と、WindowsのAPIで使用されています。の何が問題なのでしょうか? wchar_twstring というように、国際化に対応したい場合、ワイド文字の代わりとなるものはありますか?

どのように解決するのですか?

wchar_tとは何ですか?

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

wchar_t型は、サポートされるロケールの中で指定された最大の拡張文字集合の全てのメンバに対して異なるコードを表すことができる明確な型である (22.3.1)。

- C++ [基本.基礎] 3.9.1/5

これは は、wchar_t が全てのロケールの文字を同時に表現するのに十分な大きさであることを要求しているわけではありません。つまり、wchar_tに使われるエンコーディングはロケールによって異なる可能性があります。つまり、あるロケールを使って文字列をwchar_tに変換し、別のロケールを使ってcharに戻すということは必ずしもできないのです。 1

wchar_tをすべてのロケール間で共通の表現として使うことが、実際のところwchar_tの主な用途であるように思われます。

wchar_tの元々の意図と目的は、文字列のコード単位からテキストの文字への一対一のマッピングを必要とするように定義することによってテキスト処理を単純化することでした。

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

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

wchar_tは現在どのように使われているのでしょうか?

あまりないですね、ポータブルなコードには。もし __STDC_ISO_10646__ が定義されている場合、wchar_t の値は全てのロケールにおいて同じ値を持つ Unicode コードポイントを直接表します。これは、先に述べたロケール間変換を安全に行うことができます。なぜなら、ほとんどのUNIXプラットフォームでは定義されていますが、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 のマルチコード ユニット表現はより一般的であるため、NFC や NFKC で UTF-32 に固執するよりも、このような可変幅の文字表現を扱うコードのバグに気づいて修正する可能性が高いため、より良いと見なされるかもしれません。

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

いくつかのソフトウェアで使用されている別の選択肢は、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 は char から wchar_t へのレガシーエンコーディングを前提とした古い Windows プログラムを移行するためのもので、プログラムが以前の千年紀に書かれたものでない限り、忘れるのが一番です。TCHARは移植性がなく、本質的にエンコーディングやデータ型さえも特定できないので、TCHAR以外のAPIでは使用できません。TCHARの目的はwchar_tへの移行であり、それは良い考えではないことは前述しましたので、TCHARを使うことには何の価値もありません。


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

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