848

std::stringとの違いがわかりませんstd::wstringwstringUnicode文字などのワイド文字をサポートしていることは知っています。次の質問があります。

  1. いつ使い替えるべきですstd::wstringstd::string
  2. std::string特殊文字を含むASCII文字セット全体を保持できますか?
  3. std::wstringすべての一般的なC++コンパイラでサポートされていますか?
  4. 正確には「ワイド文字」とは何ですか?
4

12 に答える 12

1095

stringwstring

std::stringは、およびにbasic_stringテンプレート化されています。charstd::wstringwchar_t

char対。wchar_t

char文字、通常は8ビット文字を保持することになっています。 wchar_tはワイド文字を保持することになっているため、注意が必要です。Linuxではawchar_tは4バイトですが、Windowsでは2バイトです。

では、 Unicodeはどうですか?

問題は、どちらcharwchar_tユニコードに直接結び付けられていないことです。

Linuxでは?

LinuxOSを見てみましょう。私のUbuntuシステムはすでにUnicodeに対応しています。char文字列を操作する場合、 UTF-8(つまり、Unicode文字列のchars)でネイティブにエンコードされます。次のコード:

#include <cstring>
#include <iostream>

int main()
{
    const char text[] = "olé";


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

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

    for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
    {
        unsigned char c = static_cast<unsigned_char>(text[i]);
        std::cout << " " << static_cast<unsigned int>(c);
    }

    std::cout << "\n\n";

    // - - -

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

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

    std::cout << "sizeof(wtext)   : " << sizeof(wtext) << "\n";
    std::cout << "wcslen(wtext)   : " << wcslen(wtext) << "\n";

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

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

    std::cout << "\n\n";
}

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

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

の「olé」テキストcharは、実際には110、108、195、169の4つの文字で構成されています(末尾のゼロは数えません)。wchar_t(演習としてコードを学習させます)

したがって、charLinuxで作業する場合は、通常、知らないうちにUnicodeを使用することになります。そして、でstd::string動作するcharように、std::stringすでにユニコード対応です。

std::stringC文字列APIと同様に、「olé」文字列は3文字ではなく4文字であると見なされることに注意してください。したがって、UTF-8では文字の組み合わせが禁止されているため、Unicode文字を切り捨てたり再生したりする場合は注意が必要です。

Windowsでは?

Windowsでは、これは少し異なります。Win32は、Unicodeが登場する前に、世界中で作成されcharたさまざまな文字セット/コードページで動作する多くのアプリケーションをサポートする必要がありました。

したがって、彼らの解決策は興味深いものでした。アプリケーションがで動作する場合char、char文字列はマシンのローカルcharset / codepageを使用してGUIラベルにエンコード/印刷/表示されますが、これは長い間UTF-8ではありませんでした。たとえば、「olé」はフランス語にローカライズされたWindowsでは「olé」になりますが、キリル文字にローカライズされたWindowsでは「olé」になります(Windows-1251を使用している場合は「olй」 )。したがって、「履歴アプリ」は通常、同じように機能します。

Unicodeベースのアプリケーションの場合、Windowswchar_tは2バイト幅のを使用し、 UTF-16でエンコードされます。UTF-16は2バイト文字でエンコードされたUnicodeです(または、少なくとも、サロゲートペアがないUCS-2としたがって、BMP外の文字(> = 64K))。

を使用するアプリケーションcharは「マルチバイト」(各グリフが1つ以上で構成されているためchar)と呼ばれ、使用しているアプリケーションwchar_tは「ワイド文字」(各グリフが1つまたは2つで構成されているため)と呼ばれますwchar_t。詳細については、 MultiByteToWideCharおよびWideCharToMultiByteWin32変換APIを参照してください。

したがって、Windowsで作業している場合は、 ( GTKQTなどのようにそれを隠すフレームワークを使用しない限り)ひどく使用したいと思うでしょう。事実、Windowsは舞台裏で文字列を処理するため、履歴アプリケーションでさえ、 API (Win32 GUIでラベルを設定するための低レベルAPI関数)を使用すると文字列が変換されます。wchar_twchar_tcharwchar_tSetWindowText()

メモリの問題?

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

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

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

全体として、UTF-16はほとんどの場合1文字あたり2バイト、場合によっては4バイトを使用します(ある種の難解言語グリフ(クリンゴン?エルフ?)を扱っている場合を除く)が、UTF-8は1〜4バイトを使用します。

詳細については、 https://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16を参照してください。

結論

  1. std::stringよりもstd::wstringを使用する必要があるのはいつですか?

    Linuxでは?ほとんどは決してない (§)。Windowsでは?ほとんどいつも (§)。クロスプラットフォームコードについて?ツールキットによって異なります...

    (§):ツールキット/フレームワークを使用しない限り、別の言い方をします

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

    注意:Astd::stringは、「バイナリ」バッファを保持するのに適していますが、astd::wstringはそうではありません。

    Linuxでは?はい。Windowsでは?Windowsユーザーの現在のロケールで使用できる特殊文字のみ。

    編集(Johann Gerellからのコメントの後):すべてのベースの文字列(それぞれが0から255までの数値)を処理するには 、astd::stringで十分です。だが:charchar

    1. ASCIIは0から127まで行くことになっています。より高いcharsはASCIIではありません。
    2. char0から127までは正しく保持されます
    3. 128から255までは、charエンコード(Unicode、非Unicodeなど)に応じて意味がありますが、UTF-8でエンコードされている限り、すべてのUnicodeグリフを保持できます。
  3. std::wstringほとんどすべての一般的なC++コンパイラでサポートされていますか?

    ほとんどの場合、Windowsに移植されたGCCベースのコンパイラを除きます。これは私のg++4.3.2(Linuxの場合)で動作し、Visual C++6以降はWin32でUnicodeAPIを使用していました。

  4. 正確にワイド文字とは何ですか?

    C / C ++では、wchar_t単純な文字タイプよりも大きい文字タイプが記述されていcharます。これは、インデックス(Unicodeグリフなど)が255(または127、場合によっては...)より大きい文字を内部に配置するために使用されることになっています。

于 2008-12-31T12:47:29.907 に答える
94

std::wstringインターフェイスで必要な場合を除き、Windows またはその他の場所では避けることをお勧めします。

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

主に UI アプリケーションなど、アプリケーションが API 呼び出し中心でない限り、Unicode 文字列を std::string に格納し、UTF-8 でエンコードして、API 呼び出しの近くで変換を実行することをお勧めします。この記事で概説されている利点は、特に複雑なアプリケーションでは、変換の明らかな煩わしさを上回ります。これは、マルチプラットフォームおよびライブラリ開発の場合に二重に当てはまります。

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

  1. いくつかの弱い理由。これは、ワイド文字が Unicode をサポートする適切な方法であると信じられていた歴史的な理由から存在します。現在は、UTF-16 文字列を優先する API とのインターフェイスに使用されています。そのような API 呼び出しのすぐ近くでのみ使用します。
  2. これは std::string とは関係ありません。どんなエンコーディングを入れても保持できます。唯一の問題は、そのコンテンツをどのように扱うかです。私の推奨は UTF-8 で、すべての Unicode 文字を正しく保持できます。これは Linux では一般的な方法ですが、Windows プログラムでも行うべきだと思います。
  3. いいえ。
  4. ワイド文字は紛らわしい名前です。Unicode の初期の頃、文字は 2 バイトでエンコードできると信じられていたため、この名前が付けられました。今日では、「2 バイト長の文字の任意の部分」を表します。UTF-16 は、このようなバイト ペア (別名ワイド文字) のシーケンスと見なされます。UTF-16 の文字は、1 つまたは 2 つのペアを取ります。
于 2009-12-29T16:14:55.650 に答える
39

したがって、ここにいるすべての読者は、事実、状況について明確に理解している必要があります。そうでない場合は、paercebal の非常に包括的な回答を読む必要があります[ところで: ありがとう!]。

私の実用的な結論は驚くほど単純です。C++ (および STL) の「文字エンコーディング」はすべて、実質的に壊れていて役に立たないということです。マイクロソフトのせいにするかどうかに関係なく、とにかく役に立ちません。

私の解決策は、詳細な調査、多くの欲求不満、およびその結果としての経験の結果、次のとおりです。

  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 インスタンスを使用します。文字ベースの処理は、NON-multibyte-representation で行う必要があります。シンプル、高速、簡単です。

  6. UTF-8 と UCS-2 の間で相互に変換するための 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,...};、UCS2 から & への変換用の適切なコード) の助けを借りて実現できます。

  • UCS-2 では不十分な場合は、UCS-4 に切り替えます ( typedef std::basic_string<uint32_t> UCS2String)

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

高度なもの用。

于 2011-11-07T06:07:09.977 に答える
26
  1. 文字列にワイド文字を格納したい場合。wide実装によって異なります。Visual C ++は、正しく覚えていればデフォルトで16ビットになりますが、GCCはターゲットに応じてデフォルトになります。ここでは32ビット長です。wchar_t(ワイド文字タイプ)はUnicodeとは関係がないことに注意してください。実装がそのロケールでサポートする最大の文字セットのすべてのメンバーを、少なくともcharまで格納できることが保証されているだけです。エンコーディングを使用するためにUnicode文字列をうまく保存することもできます。ただし、ユニコードコードポイントの意味は理解できません。それでstd::stringutf-8str.size()文字列内の論理文字の量はわかりませんが、その文字列/wstringに格納されているcharまたはwchar_t要素の量だけがわかります。そのため、gtk / glib C ++ラッパーの人々は、Glib::ustringutf-8を処理できるクラスを開発しました。

    wchar_tの長さが32ビットの場合、Unicodeエンコーディングとして使用でき、固定(utf-32は固定長)エンコーディングを使用してUnicode文字列をutf-32格納および処理できます。これは、wstringのs.size()関数が適切な量のwchar_t要素論理文字を返すことを意味します。

  2. はい、charは常に少なくとも8ビット長です。つまり、すべてのASCII値を格納できます。
  3. はい、すべての主要なコンパイラがそれをサポートしています。
于 2008-12-31T11:48:20.757 に答える
7

std::string を頻繁に使用して、まったく問題なくutf-8文字を保持します。utf-8 をネイティブ文字列型として使用する API とやり取りする場合にも、これを行うことを心からお勧めします。

たとえば、コードを Tcl インタープリターとやり取りするときに utf-8 を使用します。

主な注意点は、std::string の長さであり、もはや文字列の文字数ではありません。

于 2008-12-31T04:33:23.913 に答える
6

良い質問です!データをファイルに保存したり、ネットワーク経由でデータを転送したりするためのDATA ENCODING (場合によってはCHARSETも関与) はMEMORY EXPRESSION MECHANISMだと思うので、この質問に次のように答えます。

1. std::string よりも std::wstring を使用する必要があるのはいつですか?

プログラミング プラットフォームまたは API 関数が 1 バイトのものであり、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 オクテットが「123abc&*_&」などの印刷可能なテキストを含む 1 つの文字を表すことを意味します。エディターや端末を混乱させないようにします。また、他のいくつかの国では、独自の「ASCII」文字セットを拡張しています。たとえば、中国語では、2 オクテットを使用して 1 文字を表します。

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

たぶん、またはほとんど。私が使用したもの: VC++6 および GCC 3.3、はい

4. 「ワイド文字」とは正確には何ですか?

ワイド文字は、ほとんどの場合、すべての国の文字を保持するために 2 オクテットまたは 4 オクテットを使用することを示します。2オクテットのUCS2が代表的なサンプルで、さらに例えば英語の「a」では、そのメモリは0x0061の2オクテットです(対ASCIIの「a」のメモリは1オクテットの0x61)。

于 2013-10-29T09:56:25.017 に答える
5
  1. 'ワイド'(Unicode)文字を保存したい場合。
  2. はい:255個(0を除く)。
  3. はい。
  4. ここに紹介記事があります:http://www.joelonsoftware.com/articles/Unicode.html
于 2008-12-31T04:16:01.123 に答える
2

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

stringaと aの唯一の違いwstringは、格納する文字のデータ型です。char文字列には、サイズが少なくとも 8 ビットであることが保証されている s が格納されるため、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 はおそらく変換をサポートしています。

于 2011-09-11T09:28:00.243 に答える
1
  1. ASCIIだけでなくUnicode文字列を使用したい場合は、国際化に役立ちます
  2. はい、でも0ではうまくいきません
  3. 知らないものに気づいていない
  4. ワイド文字は、Unicode文字の固定長表現を処理するコンパイラ固有の方法です。MSVCの場合は2バイト文字であり、gccの場合は4バイトであると理解しています。およびhttp://www.joelonsoftware.com/articles/Unicode.htmlの+1
于 2008-12-31T04:16:48.593 に答える
-3

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

4) ワイド文字については、こちらを ご覧ください http://en.wikipedia.org/wiki/Wide_character

于 2008-12-31T04:24:41.853 に答える
-7

ワイド文字を使用してはいけないのはいつですか?

1990年より前にコードを書いているとき。

明らかに、私はひっくり返っていますが、実際には、21世紀になりました。127文字では十分ではなくなってから長い年月が経ちました。はい、UTF8を使用できますが、なぜ頭痛の種に悩まされるのでしょうか。

于 2009-06-10T23:26:56.517 に答える