677


385

std :: wstring VS std :: string
私は `std

string`と` std :: wstring`の違いを理解することができません。 私は `wstring`がUnicode文字のようなワイド文字をサポートすることを知っています。 以下の質問があります。

. いつstd

stringの上でstd :: wstringを使うべきですか?

. `std

string`はASCII文字セット全体を保持できますか? 特殊文字?

. `std

wstring`はすべてのポピュラーなCコンパイラでサポートされていますか?

  1. 「ワイド文字」とは何ですか?

12 Answer


926


「ひも」? wstring

`std

string`は、` char`をテンプレートとしたhttp://en.cppreference.com/w/cpp/string/basic_string [basic_string]であり、http://をテンプレートとした` std :: wstring`です。 en.wikipedia.org/wiki/Wide_character [wchar_t]。

「char」と wchar_t

char`は文字、通常8ビット文字を保持することになっています。 `wchar_t`はワイド文字を保持することになっています、そしてそれから、事は慎重になります:Linuxでは wchar_t`は4バイトですが、Windowsではそれは2バイトです。

では、http://en.wikipedia.org/wiki/Unicode[Unicode]はどうでしょうか。

問題は char`も wchar_t`もUnicodeに直接結び付けられていないことです。

Linuxでは?

Linux OSを取り上げましょう。私のUbuntuシステムはすでにUnicode対応です。 私が文字列を扱うとき、それはネイティブにhttp://en.wikipedia.org/wiki/UTF-8 [UTF-8](すなわち、 Unicode文字列) 次のコード

#include
#include

int main(int argc, char* argv[])
{
   const char text[] = "olé" ;


   std::cout << "sizeof(char)    : " << sizeof(char) << std::endl ;
   std::cout << "text            : " << text << std::endl ;
   std::cout << "sizeof(text)    : " << sizeof(text) << std::endl ;
   std::cout << "strlen(text)    : " << strlen(text) << std::endl ;

   std::cout << "text(ordinals)  :" ;

   for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
   {
      std::cout << " " << static_cast(
                              static_cast(text[i])
                          );
   }

   std::cout << std::endl << std::endl ;

   // - - -

   const wchar_t wtext[] = L"olé" ;

   std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl ;
   //std::cout << "wtext           : " << wtext << std::endl ; <- error
   std::cout << "wtext           : UNABLE TO CONVERT NATIVELY." << std::endl ;
   std::wcout << L"wtext           : " << wtext << std::endl;

   std::cout << "sizeof(wtext)   : " << sizeof(wtext) << std::endl ;
   std::cout << "wcslen(wtext)   : " << wcslen(wtext) << std::endl ;

   std::cout << "wtext(ordinals) :" ;

   for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
   {
      std::cout << " " << static_cast(
                              static_cast(wtext[i])
                              );
   }

   std::cout << std::endl << std::endl ;

   return 0;
}

次のテキストを出力します。

sizeof(char)    : 1
text            : olé
sizeof(text)    : 5
strlen(text)    : 4
text(ordinals)  : 111 108 195 169

sizeof(wchar_t) : 4
wtext           : UNABLE TO CONVERT NATIVELY.
wtext           : ol�
sizeof(wtext)   : 16
wcslen(wtext)   : 3
wtext(ordinals) : 111 108 233

`char`の"olé "というテキストは、実際には110、108、195、および169の4文字で構成されています(末尾のゼロは含まれません)。 (練習として `wchar_t`コードを勉強しましょう)

そのため、Linuxで `char`を扱うときは、知らないうちにUnicodeを使うことになります。 そして `std

string`は` char`と連携するので、 `std :: string`はすでにUnicode対応です。

Cの文字列APIのように `std

string`は"olé "文字列は3文字ではなく4文字であるとみなします。 そのため、Unicodeの文字を切り詰めたり再生したりするときは注意が必要です。文字の組み合わせによってはUTF-8では使用できないためです。

Windowsでは?

Windowsでは、これは少し異なります。 Win32は、 `char`と、さまざまなhttp://en.wikipedia.org/wiki/Character_encoding[charsets]/http://en.wikipedia.org/wiki/Code_page[codepages]で動作する多くのアプリケーションをサポートする必要がありました。 Unicodeが出現する前は、世界中で

アプリケーションが `char`を扱う場合、char文字列はマシン上のローカルのcharset / codepageを使ってGUIラベルにエンコード/印刷/表示されます。 たとえば、フランス語にローカライズされたWindowsでは "olé"は "olé"になりますが、キリル文字にローカライズされたWindowsでは "olé"は異なります(http://en.wikipedia.org/wiki/Windows-を使用する場合は "olй")。 1251 [Windows-1251])。 したがって、「歴史的アプリ」は通常、依然として同じ古い方法で動作します。

Unicodeベースのアプリケーションでは、Windowsは2バイト幅の `wchar_t`を使い、http://en.wikipedia.org/wiki/UTF-16[UTF-16]でエンコードされています。バイト文字(または少なくとも、最も互換性のあるUCS-2、これはほとんど同じIIRCです)。

char`を使うアプリケーションは「マルチバイト」と呼ばれ(各グリフは1つ以上の char`から構成されているため)、 `wchar_t`を使うアプリケーションは「widechar」と呼ばれます。 MultiByteToWideCharおよびhttps://msdn.microsoft.com/ja-jp/library/dd374130.aspx[WideCharToMultiByte]のWin32変換APIを参照してください。詳しくは

ですから、もしあなたがWindowsで作業しているのであれば、あなたは* whar_tを*ひどく*使用することを望みます(あなたがそれを隠しているフレームワークを使用しない限り、http://en.wikipedia.org/wiki/GTK%2B[GTK]またはhttp:/ /en.wikipedia.org/wiki/Qt_(toolkit)[QT] …​)。 実際のところ、Windowsは wchar_t`文字列を扱うので、歴史的なアプリケーションでも SetWindowText() (ラベルを設定するための低レベルAPI関数)のようなAPIを使うと char`文字列は `wchar_t`に変換されます。 Win32 GUI上で)

メモリの問題?

UTF-32は1文字あたり4バイトなので、UTF-8テキストとUTF-16テキストの方が常にUTF-32テキストよりも少ないか同じ量のメモリを使用する場合(および通常はそれ以下)、追加する必要はほとんどありません。 )

メモリの問題がある場合は、ほとんどの西洋言語よりもUTF-8テキストの方が同じUTF-16テキストよりもメモリの使用量が少ないことを知っておく必要があります。

それでも、他の言語(中国語、日本語など)では、使用されるメモリーは同じか、UTF-8の場合はUTF-16の場合よりもわずかに大きくなります。

全体として、UTF-16は1文字あたり2バイト、時折4バイトを使用します(ある種の難解な言語のグリフを扱っているのでなければ(Klingon?) UTF-8は1から4バイトまでを使いますが、長老?

詳しくはhttp://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16をご覧ください。

結論

  1. * std :: wstringをstd :: stringで使用する必要がある場合_ * Linuxでは? ほとんどは決してない (§)。 Windowsでは? ほとんどいつも (§)。 クロスプラットフォームのコードでは? あなたのツールキットによります…​ (§):ツールキット/フレームワークを使わない限り

  2. * _`std :: string`は、特殊文字を含むすべてのASCII文字セットを保持できますか

    characters?_ * +注意:「std

    string」は「バイナリ」バッファを保持するのに適していますが、「std :: wstring」はそうではありません! Linuxでは? Yes. Windowsでは? Windowsユーザーの現在のロケールに使用できるのは特殊文字のみです。 編集(https://stackoverflow.com/users/6345/johann-gerell [Johann Gerell]からのコメントの後): std :: string`はすべての char`ベースの文字列(それぞれの文字列を扱うのに十分) `char`は0から255までの数字です。 But:

  3. ASCIIは0から127になるはずです。 上位の「char」はASCIIではありません。

  4. 0から127までの `char`は正しく保持されます

  5. 128から255の `char`には、 エンコーディング(ユニコード、非ユニコードなど)ですが、UTF-8でエンコードされている限り、すべてのUnicodeグリフを保持できます。

  6. * `std :: wstring`は、ほとんどすべての一般的なC ++コンパイラでサポートされていますか? * +主に、Windowsに移植されたGCCベースのコンパイラを除きます。 これは私のg 4.3.2(Linux下)で動作し、私はVisual C 6以降Win32上でUnicode APIを使用しました。

  7. * ワイド文字とは何ですか? * + C / C ++では、これは単純な char`文字タイプよりも大きい wchar_t`と書かれた文字タイプです。 それは、インデックス(Unicodeグリフのような)が255(または127に依存して、127)より大きい文字を中に入れるために使われることになっています。


54


私は、Windowsや他の場所で `std

wstring`を避けることをお勧めします。ただし、インターフェースで必要な場合、またはWindows API呼び出しとそれぞれの構文変換に近いコード化変換の近くでは必要ありません。

私の見解は、私が共著者であるhttp://utf8everywhere.orgに要約されています。

アプリケーションがAPI呼び出し中心のものでない限り、 主にUIアプリケーションでは、提案はUnicode文字列をstd

stringに格納し、UTF-8でエンコードし、API呼び出しの近くで変換を実行することです。 この記事で概説されている利点は、特に複雑なアプリケーションにおいて、見かけの変換の煩わしさを上回るものです。 これは、マルチプラットフォームやライブラリ開発にとっては二重のことです。

そして今、あなたの質問に答える:

  1. いくつかの弱い理由 歴史的な理由で存在します。 Unicodeをサポートする適切な方法であると信じられていました。 これは現在、UTF-16文字列を好むAPIのインターフェースに使用されています。 私はそのようなAPI呼び出しのすぐ近くでのみそれらを使用します。

  2. これはstd :: stringとは関係ありません。 どんなエンコーディングでも保持できます 入れます 唯一の問題は、あなたがその内容をどのように扱うかということです。 私のお勧めはUTF-8なので、すべてのUnicode文字を正しく保持できるでしょう。 これはLinux上では一般的な方法ですが、Windowsプログラムでも同様に行うべきだと思います。

  3. No.

  4. ワイド文字はわかりにくい名前です。 ユニコードの初期には、 文字は2バイトでエンコードできると考えられていたため、名前が付けられました。 今日、それは「2バイト長の文字の任意の部分」を表します。 UTF-16は、このようなバイトペアのシーケンス(ワイド文字とも呼ばれます)と見なされます。 UTF-16の文字は1つか2つのペアを取ります。


36


ですから、ここにいるすべての読者は、事実、状況について明確に理解しているはずです。 そうでなければ、それならあなたは* pacecebalの非常に包括的な答えを読まなければならない* [ところで:ありがとう!]。

私の実用的な結論は驚くほど簡単です。C(およびSTL)の「文字エンコーディング」に関するものはすべて壊れていて役に立ちません。 とにかく助けにはならないだろう、Microsoftのせいかどうか。

私の解決策は、徹底的な調査の結果、多くのフラストレーションとその結果としての経験は以下の通りです。

  1. 受け入れ、エンコードについては自分で責任を負う必要があること そして変換のもの(そして、あなたはそれの多くがかなり些細なことがわかります)

  2. UTF-8でエンコードされた文字列にはstd :: stringを使用します(

    `typedef std

    string UTF8String`)

  3. そのようなUTF8Stringオブジェクトは単なる愚かだが、安いことを受け入れる 容器。 その中の文字に直接アクセスしたり、文字を直接操作したりしないでください(検索、置換など)。 マルチバイト文字列のテキスト操作アルゴリズムを書くのに時間を無駄にしたくないかもしれません。 たとえ他の人がそのようなばかげたことをすでにしたとしても、それをしないでください! なるがままに! (まあ、それが理にかなっているシナリオがあります…​ そのためにはICUライブラリを使用してください。

  4. UCS-2エンコード文字列にはstd :: wstringを使用します

    ( `typedef std

    wstring UCS2String`)-これは妥協であり、WIN32 APIが導入した混乱への譲歩です。 UCS-2は私たちの大部分にとって十分です(詳細は後ほど…​)。

  5. 文字単位のアクセスが行われる場合は常にUCS2Stringインスタンスを使用します 必須(読み取り、操作など)。 文字ベースの処理はすべて、非マルチバイト表現で行う必要があります。 それは簡単、速く、簡単です。

  6. 2つのユーティリティ関数を追加して、UTF-8と UCS-2:+

UCS2String ConvertToUCS2( const UTF8String &str );
UTF8String ConvertToUTF8( const UCS2String &str );

変換は簡単です。Googleがここで助けになるはずです…​

それでおしまい。 メモリが貴重であり、すべてのUTF-8 I / Oに対して、UTF8Stringを使用してください。 文字列を解析または操作する必要がある場合は、必ずUCS2Stringを使用してください。 これら2つの表現はいつでも変換できます。

*代替案

  • からの変換 ISO − 8859−1)は、平易な翻訳表を用いて実現することができる。 `const wchar_t tt_iso88951 [256] = {0,1,2、…​};`とに変換するための適切なコード

  • UCS-2で十分でない場合、UCS-4に切り替える

    ( `typedef std

    basic_string UCS2String`)

  • ICUまたは他のUnicodeライブラリ


25


  1. ワイド文字を文字列に格納したい場合 「広い」

    実装に依存します。 GCCのデフォルトはターゲットによって異なりますが、Visual Cのデフォルトは16ビットです。 ここは32ビットです。 wchar_t(ワイド文字型)はUnicodeとは無関係です。 実装がそのロケールでサポートする最大の文字セットのすべてのメンバーを、少なくともcharと同じ長さだけ格納できることが保証されているだけです。 utf-8`エンコーディングを使って文字列を std

    string`に細かく_store_することができます。 しかし、それはUnicodeコードポイントの意味を理解しません。 そのため str.size()`はあなたの文字列中の論理的な文字数を与えるのではなく、単にその文字列/ wstringに格納されているcharやwchar_t要素の量を与えるだけです。 そのため、gtk / glib Cラッパーの人々はhttp://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/classGlib_1_1ustring.html [`Glib :: ustring]クラスを開発することができます。 UTF-8を処理します。 wchar_tの長さが32ビットであれば、Unicodeエンコーディングとして `utf-32`を使うことができ、固定(utf-32は固定長)エンコーディングを使ってユニコード文字列を格納することができます。 これはあなたのwstringの `s.size()`関数が正しい量のwchar_t要素を返すことを意味します。

  2. はい、charは常に少なくとも8ビット長です。つまり、すべてを格納できます。 ASCII値。

  3. はい、すべての主要なコンパイラがそれをサポートしています。


5


私は何の問題もなくutf-8文字を保持するためにstd

stringを頻繁に使用します。 ネイティブの文字列型としてutf-8を使用しているAPIとインターフェースする場合は、これを行うことを心からお勧めします。

たとえば、私のコードをTclインタプリタとインタフェースするときは、utf-8を使います。

主な注意点はstd

stringの長さで、もはや文字列の文字数ではありません。


3


  1. ワイド(Unicode)文字を保存したいとき。

  2. はい:それらのうち255(0を除く)。

  3. はい。

  4. これが紹介記事です。http://www.joelonsoftware.com/articles/Unicode.html


2


256種類の文字だけでは満足できないアプリケーションには、ワイド文字(8ビット以上)、またはUTF-8などの可変長エンコーディング(C用語ではマルチバイトエンコーディング)のどちらを使用するかの選択肢があります。 ワイド文字は一般に可変長エンコーディングよりも多くのスペースを必要としますが、処理は高速です。 大量のテキストを処理する多言語アプリケーションは通常、テキストを処理するときにワイド文字を使用しますが、ディスクに格納するときはUTF-8に変換します。

string`と wstring`の唯一の違いはそれらが格納する文字のデータ型です。 文字列はサイズが少なくとも8ビットであることが保証されている `char`を格納します。 ASCII、ISO-8859-15、またはUTF-8のテキスト。 規格では、文字セットやエンコーディングについては何も言われていません。

事実上すべてのコンパイラは、最初の128文字がASCIIに対応する文字セットを使用します。 これは、UTF-8エンコーディングを使用するコンパイラにも当てはまります。 UTF-8やその他の可変長エンコーディングで文字列を使用するときに注意すべき重要なことは、インデックスと長さは文字数ではなくバイト数で測定されるということです。

wstringのデータ型は `wchar_t`であり、そのサイズは標準では定義されていません、少なくともcharと同じくらいの大きさでなければならない、通常16ビットか32ビットです。 wstringは、実装定義のワイド文字エンコーディングでテキストを処理するために使用できます。 エンコードは標準では定義されていないため、文字列とwstringの間の変換は簡単ではありません。 wstringが固定長エンコーディングを持つと仮定することもできません。

多言語サポートが不要な場合は、通常の文字列だけを使用しても問題ありません。 一方、グラフィカルアプリケーションを作成している場合は、APIがワイド文字のみをサポートすることがよくあります。 その場合は、おそらくテキストを処理するときに同じワイド文字を使用します。 UTF-16は可変長エンコーディングであることに注意してください。つまり、文字数を返すために `length()`を想定することはできません。 APIがUCS-2などの固定長エンコードを使用している場合は、処理が簡単になります。 ワイド文字とUTF-8との間の変換は、移植性の高い方法で行うのは困難ですが、やはり、ユーザーインターフェースAPIがおそらくその変換をサポートしています。


1


  1. ASCIIだけでなくUnicode文字列を使いたい場合、国際化に役立ちます

  2. はい、でも0ではうまくいかない

  3. そうでないものを意識していない

  4. ワイド文字は、Unicode文字の固定長表現を処理するためのコンパイラー固有の方法です。MSVCの場合は2バイト文字、gccの場合は4バイトです。 そしてhttp://www.joelonsoftware.com/articles/Unicode.htmlの1


0


1)Gregが述べたように、wstringは国際化に役立ちます。それはあなたが英語以外の言語であなたの製品をリリースする時です。

4)ワイド文字* http://en.wikipedia.org/wiki/Wide_character*のためにこれをチェックしてください


0


いい質問ですね。 データエンコーディング(時には* CHARSET も含まれる)は、データをファイルに保存したりネットワークを介してデータを転送したりするための MEMORY EXPRESSION *メカニズムであると思います。

  • 1 いつstd :: stringの上にstd :: wstringを使うべきですか?*

    プログラミングプラットフォームやAPI関数がシングルバイトで、Windowsの.REGファイルやネットワークの2バイトストリームなどのUnicodeデータを処理または解析する場合は、std

    wstring変数を宣言して簡単にできます。それらを処理します。 例:wstring ws = L "中国a"(6オクテットメモリ:0x4E2D 0x56FD 0x0061)、ws [0]を使用して文字 '中’を取得し、ws [1]を使用して文字 '中’を取得し、ws [2]を取得します。文字 'a’などを取得する

  • 2 std :: stringは特殊文字を含むASCII文字セット全体を保持できますか?*

はい。 しかし注意してください:アメリカのASCIIは、それぞれの0x00〜0xFFオクテットが1文字を表していることを意味します。 そして他のいくつかの国では独自の "ASCII"文字セットを拡張しています。 中国語、1文字を表すのに2オクテットを使用します。

  • 3. std :: wstringはすべての一般的なCコンパイラでサポートされていますか?*

たぶん、あるいはほとんど。 私は使ったことがある:VC 6とGCC 3.3、YES

  • 4 まさに「ワイド文字」とは何ですか?*

ワイド文字は、主に2オクテットまたは4オ​​クテットを使用してすべての国の文字を保持することを示します。 2オクテットのUCS2は代表的なサンプルであり、さらに、例えば、C。 英語の 'a'、そのメモリは0x0061の2オクテットです(ASCIIでは 'a’のメモリは1オクテットの0x61です)。