std :: wstring VS std :: string


741

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

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

10
ASCII文字セットには「特殊」文字は多くありませんが、最もエキゾチックなものはおそらく `(バッククォート)です。std :: stringは、すべてのUnicode文字(通常、8ビット文字)の約0.025%を保持できます
MSalters 2009年

3
:ワイド文字と使用するタイプは、ここで見つけることができますについての良い情報programmers.stackexchange.com/questions/102205/...
ヤリブ

14
さて、そして私たちが2012年にいるので、utf8everywhere.orgが書かれました。C ++ / Windowsの権利と誤りに関するすべての質問にほぼ答えます。
Pavel Radzivilovsky 2012年

42
@MSalters:std :: stringは、CHAR_BITが8であっても、すべてのUnicode文字の100%を保持できます。これは、システムレベルでUTF-8である可能性があるstd :: stringのエンコーディングに依存します(Windowsを除くほぼすべての場所と同様) )またはアプリケーションレベルで。ネイティブナローエンコーディングはUnicodeをサポートしていませんか?問題ありません。使用せず、代わりにUTF-8を使用してください。
Yakov Galka

8
このトピックに関する優れた資料
Timothy Shields

回答:


992

stringwstring

std::stringされbasic_stringにテンプレートchar、およびstd::wstringwchar_t

charwchar_t

char文字、通常は8ビット文字を保持することになっています。
wchar_tワイド文字を保持することになっているため、状況が複雑になります
。Linuxでは、a wchar_tは4バイトですが、Windowsでは2バイトです。

何についてのUnicode、その後?

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

Linuxでは?

Linux OSを取り上げましょう。私のUbuntuシステムはすでにユニコードに対応しています。char文字列を操作すると、UTF-8(つまり、文字のUnicode文字列)でネイティブにエンコードされます。次のコード:

#include <cstring>
#include <iostream>

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<unsigned int>(
                              static_cast<unsigned char>(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<unsigned int>(
                              static_cast<unsigned short>(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

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

したがって、charLinuxで作業する場合、通常、Unicodeを知らなくても使用する必要があります。でstd::string動作するcharようにstd::string、すでにunicode対応です。

std::stringC文字列APIのように、「OLE」の文字列を検討するには、4つの文字ではなく、3を持っています。したがって、UTF-8では一部の文字の組み合わせが禁止されているため、Unicode文字で切り捨て/再生する場合は注意が必要です。

Windowsでは?

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

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

Unicodeベースのアプリケーションの場合、Windows wchar_tは2バイト幅のを使用し、UTF-16でエンコードされます。UTF-16は、2バイト文字にUnicodeでエンコードされています(少なくとも、ほとんどの場合、ほとんど互換性のあるUCS-2です)。同じことIIRC)。

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

したがって、Windowsで作業している場合は、使用したくありwchar_tません(GTK +QTなどの非表示のフレームワークを使用しない限り)。実際、Windowsは舞台裏でwchar_t文字列を処理するため、歴史的なアプリケーションでさえ、(Win32 GUIでラベルを設定するための低レベルAPI関数)などのAPIを使用するとchar文字列が変換されwchar_tますSetWindowText()

メモリの問題?

UTF-32は1文字あたり4バイトであるため、UTF-8テキストとUTF-16テキストが常に使用するメモリの量は、UTF-32テキストよりも少ないか、同じである(そして通常、 )。

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

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

全体として、UTF-16は文字あたり2バイト、場合によっては4バイトを使用します(何らかの難解な言語のグリフ(Klingon?Elvish?)を扱っている場合を除く)。UTF-8は1〜4バイトを消費します。

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

結論

  1. std :: stringではなくstd :: wstringを使用する必要がある場合

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

    (§):別の方法で言っているツールキット/フレームワークを使用しない限り

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

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

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

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

    1. ASCIIは0から127までであると想定されています。上位charのsはASCIIではありません。
    2. char0から127のa は正しく保持されます
    3. a char128から255までは、あなたのエンコーディング(ユニコード、非ユニコードなど)に応じた意義を持っていますが、それらはUTF-8でエンコードされているとして、限り、すべてのUnicodeグリフを保持することができるようになります。
  3. されるstd::wstringほとんどすべての人気のC ++コンパイラでサポートされていますか?

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

  4. ワイドキャラクターとは何ですか?

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


4
@gnud:おそらく、wchar_tは、UTF-16が登場する前にすべてのUCS-2文字(ほとんどのUTF-16文字)を処理するのに十分であるはずでした...または、おそらくMicrosoftは、Unicodeに簡単にアクセスできるようにするなど、POSIX以外の優先順位を持っていましたWin32でcharのコードページ使用を変更せずに。
paercebal 2009年

4
@Sorin Sbarnea:UTF-8は1〜6バイトを取る可能性がありますが、標準では明らかに1〜4バイトに制限しています。詳細については、en.wikipedia.org / wiki / UTF8#Descriptionを参照してください。
paercebal 2010年

8
この例ではLinuxとWindowsで異なる結果が生成されますが、C ++プログラムにはolè、UTF-8としてエンコードされているかどうかに関して、実装定義の動作が含まれています。さらにより多くの、あなたがすることができない理由ネイティブにストリーミングするwchar_t *には、std::cout種類が病気に形成されたプログラムが生じ互換性がありません、それはエンコーディングの使用とは何の関係もありませんのでです。特にコードを移植可能にしたい場合は、プラットフォームではなく独自のエンコーディング設定を使用するstd::stringか、std::wstring依存するかに注意してください。
ジョンライデグレン2012

14
Windowsは実際にはUTF-16を使用しており、かなり以前から、古いバージョンのWindowsではUCS-2を使用していましたが、これはもはや当てはまりません。ここで私の唯一の問題は、std::wstringWindowsで使用する必要があるという結論です。これは、私が間違っていると思うUnicode Windows APIに適しているためです。あなたの唯一の懸念がUnicode Windows APIへの呼び出しと文字列のマーシャリングではなかった場合は、確かに私はこれを一般的なケースとして購入しません。
ジョンライデグレン

15
@ジョンライデグレン::If your only concern was calling into the Unicode Windows API and not marshalling strings then sureその後、私たちは同意します。JavaScriptではなくC ++でコーディングしています。コンパイル時に実行できるときに、実行時に無駄なマーシャリングやその他の潜在的にコストのかかる処理を回避することが、その言語の中心です。WinAPIに対するコーディングと使用std::stringは、正当化されない無駄なランタイムリソースです。あなたはそれがあなたの見方であるので、それは誤りだとわかり、それは大丈夫です。私自身は、Linux側から見た目が良いという理由だけで、Windowsでペシミゼーションを使用してコードを記述しないことです。
paercebal 2012

71

std::wstringインターフェースで必要な場合を除いて、Windowsやその他の場所、またはWindows API呼び出しとそれぞれのエンコード変換の近くに構文糖衣として避けることをお勧めします。

私の見解はhttp://utf8everywhere.orgにまとめられています。

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

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

  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つのペアを取ります。

37

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

私の実用的な結論は驚くほど単純です。C++(およびSTL)の「文字エンコーディング」はすべて実質的に壊れていて役に立たないのです。マイクロソフトに責任があるかどうかはともかく、それはとにかく役に立たないでしょう。

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

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

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

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

  4. UCS-2エンコード文字列(typedef std::wstring UCS2String)にはstd :: wstringを使用してください-これは妥協であり、WIN32 APIが導入した混乱への譲歩です。ほとんどの場合、UCS-2で十分です(詳細は後で...)。

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

  6. UTF-8とUCS-2の間で相互に変換する2つのユーティリティ関数を追加します。

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

変換は簡単です、グーグルはここで役立つはずです...

それでおしまい。メモリが貴重な場所ならどこでも、すべての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ライブラリ?

上級者向け。


ちなみに、Unicodeのネイティブサポートがないことはよくありません。
ミハイダニーラ

@ Frunsi、Glib :: ustringを試したかどうか知りたいのですが、もしそうなら、どう思いますか?
Caroline Beltran 2014

@CarolineBeltran:私はGlibを​​知っていますが、それを使用したことはありません。かなり不特定のターゲットプラットフォーム(Unixoidシステム...)に限定されているため、おそらく使用することもありません。そのWindowsポートは外部のwin2unixレイヤーに基づいており、IMHOにはOSX互換レイヤーはありません。これらすべては、少なくとも私のコード(このアーチレベルでは...)に対して、明らかに間違った方向を向いています。つまり、Glibはオプションではありません
Frunsi

9
検索、置換などは、UTF-8文字列で正常に機能します(文字を表すバイトシーケンスの一部が別の文字として誤って解釈されることはありません)。実際、UTF-16とUTF-32はこれを少しも簡単にしません。3つのエンコーディングはすべて実際にはマルチバイトエンコーディングです。これは、ユーザーが認識する文字(書記素クラスタ)が任意の数のUnicodeコードポイントになる可能性があるためです。実用的なソリューションは、すべてにUTF-8を使用し、Windows APIを処理する場合にのみUTF-16に変換することです。
ダニエル

5
@Frunsi:UTF-8では、UTF-32と同じように検索と置換がうまく機能します。適切なUnicode対応のテキスト処理でマルチコードポイントの「文字」を処理する必要があるため、UTF-8のような可変長エンコーディングを使用しても、文字列処理が複雑になることはありません。だからどこでもUTF-8を使ってください。通常のC文字列関数はUTF-8で正常に動作し(Unicode文字列の序数比較に対応します)、さらに言語対応が必要な場合は、とにかくUnicodeライブラリをUTF-16 / 32で呼び出す必要があります。それからあなたを救うことはできません。
ダニエル

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

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

  2. はい、charは常に少なくとも8ビット長です。つまり、すべてのASCII値を格納できます。
  3. はい、すべての主要なコンパイラがサポートしています。

#2に興味があります。7ビットも技術的に有効だと思いましたか?または、7ビットのASCII文字を超えて何かを保存できるようにする必要がありますか?
2008

1
はい、ジャルフ。c89は、limits.h(unsigned charの場合、0..255分)のドキュメントで基本型の最小範囲を指定し、整数型の純粋なバイナリシステムを指定します。char、unsigned char、signed charの最小ビット長は8です。c++はこれらのルールを継承します。
Johannes Schaub-litb 2008

15
「つまり、wstringのs.size()関数は、適切な量のwchar_t要素と論理文字を返します。」Unicodeであっても、これは完全に正確ではありません。「論理文字」よりもコードポイントの方が正確です。UTF-32でも、特定の文字が複数のコードポイントで構成されている場合があります。
Logan Capaldo

C ++はUnicode文字セットをネイティブでサポートしていないと言っているのですか?
Mihai Danila

1
「しかし、それはユニコードコードポイントの意味を理解しません。」Windowsでは、どちらも行いませんstd::wstring
Deduplicator

5

std :: stringを頻繁に使用して、utf-8文字をまったく問題なく保持しています。ネイティブの文字列型としてutf-8を使用するAPIとのインターフェースを取るときにも、これを行うことを強くお勧めします。

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

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


1
Juan:std :: stringはすべてのUnicode文字を保持できますが、長さが誤って報告されるということですか?正しくない長さを報告している理由はありますか?

3
utf-8エンコーディングを使用する場合、単一のUnicode文字が複数のバイトで構成される場合があります。これが、標準のasciiセットのほとんどの文字を使用する場合、utf-8エンコーディングが小さい理由です。Unicodeの文字数を測定するには、特別な関数を使用する(または独自の関数を使用する)必要があります。

2
(Windows固有)ほとんどの関数は、バイトを使用する文字列がASCIIで2バイトがUnicodeであると想定します。古いバージョンのMBCS。つまり、8ビットのユニコードを格納している場合は、標準のWindows関数を呼び出すために16ビットのユニコードに変換する必要があります(ASCII部分のみを使用している場合を除く)。
Greg Domjan 2008

2
std :: stringは長さを誤って報告するだけでなく、誤った文字列も出力します。一部のUnicode文字がUTF-8で複数バイトとして表され、std :: stringがそれ自体の文字と見なされる場合、通常のstd :: string操作ルーチンは、おそらく1つの文字の誤解釈に起因するいくつかの奇妙な文字を出力します正しい性格。
Mihai Danila

2
答えを変更して、文字列はバイトのコンテナーとしてのみ考える必要があることを示し、バイトがUnicodeエンコード(UTF-8、UTF-16など)の場合は、理解できる特定のライブラリーを使用する必要があることを示しますそれ。標準の文字列ベースのAPI(長さ、サブ文字列など)はすべて、マルチバイト文字で無残に失敗します。この更新が行われた場合、反対票を削除します。
Mihai Danila 2014年

4
  1. 「ワイド」(Unicode)文字を格納する場合。
  2. はい:255(0を除く)。
  3. はい。
  4. これは紹介記事です:http : //www.joelonsoftware.com/articles/Unicode.html

11
std :: stringは0を問題なく保持できます(c_str()メソッドを呼び出す場合は注意してください)
Mr Fooz

3
厳密に言えば、charが8ビットであるとは限りません。:)#4のあなたのリンクは必読ですが、それは質問に答えるとは思いません。ワイド文字は、厳密にはユニコードとは関係ありません。それは単により広いキャラクターです。(幅はOSによって異なりますが、通常は16または32ビットです)
jalf

2
  1. ASCIIだけでなくUnicode文字列を使用したい場合、国際化に役立ちます
  2. はい、しかしそれは0ではうまくいきません
  3. 知らないものは知らない
  4. ワイド文字は、ユニコード文字の固定長表現を処理するコンパイラ固有の方法です。MSVCの場合は2バイト文字、gccの場合は4バイトであることを理解しています。およびhttp://www.joelonsoftware.com/articles/Unicode.htmlの +1

1
2. std :: stringはNULL文字を問題なく保持できます。utf-8およびワイド文字も保持できます。

@Juan:それは私を再び混乱に陥らせた。std :: stringがUnicode文字を保持できる場合、std :: wstringの特別な点は何ですか?

1
@Appu:std :: stringは、UTF-8ユニコード文字を保持できます。さまざまな文字幅を対象とする多くのUnicode標準があります。UTf8は8ビット幅です。それぞれ16ビット幅と32ビット幅のUTF-16とUTF-32もあります
Greg D

std :: wstringを使用します。固定長エンコーディングを使用する場合、各Unicode文字は1つのwchar_tになります。たとえば、Gregがリンクするときにソフトウェアアプローチにjoelを使用することを選択した場合。その場合、wstringの長さは、文字列内のUnicode文字の正確な数になります。しかし、より多くのスペースを必要とします

0 '\ 0'を保持できないとは言いませんでした。また、一部のメソッドでは、wstringのすべてのデータを含む予期した結果が得られない可能性があることを意味します。反対票に厳しい。
グレッグDomjan 2008

2

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

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


したがって、最初の段落を言い換えると、256文字を超えるアプリケーションでは、マルチバイトエンコーディングまたはmaybe_multibyte-encodingを使用する必要があります。
Deduplicator

ただし、UCS-2やUCS-4などの16ビットおよび32ビットのエンコーディングは、マルチバイトエンコーディングとは呼ばれていません。C ++標準では、マルチバイトエンコーディングとワイド文字を区別しています。ワイド文字表現は、文字ごとに固定数(通常は8を超える)ビットを使用します。1バイトを使用して最も一般的な文字をエンコードし、複数バイトを使用して残りの文字セットをエンコードするエンコーディングは、マルチバイトエンコーディングと呼ばれます。
Seppo Enarvi、2015年

コメントがずさんなコメントです。可変長エンコーディングが必要です。UTF-16は、UTF-8と同様に可変長エンコーディングです。そうではないふりをするのは悪い考えです。
Deduplicator

それは良い点です。(UCS-2の代わりに)UTF-16を格納するためにwstringを使用できなかった理由はありませんが、固定長エンコーディングの利便性は失われます。
Seppo Enarvi 2015年

2

良い質問です!DATA ENCODINGCHARSETも含まれる場合があります)は、データをファイルに保存したり、ネットワーク経由でデータを転送したりするための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文字セット全体を保持できますか?

はい。ただし、American ASCIIとは、「123abc&* _&」などの印刷可能なテキストを含む各0x00〜0xFFオクテットが1文字を意味することを意味します。エディターや端末を混乱させないようにしてください。また、他の一部の国では、独自の「ASCII」文字セットを拡張しています。たとえば、中国語では、2オクテットを使用して1文字を表します。

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

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

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

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


0

ここには非常に良い答えがいくつかありますが、Windows / Visual Studioに関していくつか追加できることがあると思います。Tisは、VS2015での私の経験に基づいています。Linuxでは、基本的に答えはstd::stringどこでもエンコードされたUTF-8を使用することです。Windows / VSではさらに複雑になります。これが理由です。Windowsは、charsを使用して格納された文字列がロケールコードページを使用してエンコードされることを想定しています。これは、ほとんどの場合、場所に応じて、ASCII文字セットの後に128個の他の特殊文字が続きます。Windows APIを使用するときだけでなく、これらの文字列が標準のC ++と相互作用する他の3つの主要な場所があることを述べさせてください。これらは文字列リテラルであり、ファイル名をstd::cout使用<<してファイル名をに渡すと出力されますstd::fstream

私はプログラマーであり、言語の専門家ではないことをここで前に示します。USC2とUTF-16は同じではないことを感謝しますが、私の目的のために、それらは交換可能であるように十分に近く、ここではそれらをそのまま使用します。どのWindowsを使用しているのか実際にはわかりませんが、通常はどちらも知る必要はありません。私はこの回答でUCS2について述べましたので、この問題を知らない人を動揺させてしまった場合は事前に申し訳ありません。問題があった場合は変更させていただきます。

文字列リテラル

コードページで表現できる文字のみを含む文字列リテラルを入力すると、VSは、コードページに基づいて、文字エンコーディングあたり1バイトでファイルに保存します。コードページを変更したり、別のコードページを使用して別の開発者にソースを提供したりした場合、(テストされていませんが)文字は異なるものになると思います。別のコードページを使用してコンピューターでコードを実行する場合、文字も変更されるかどうかはわかりません。

コードページで表現できない文字列リテラルを入力すると、VSはファイルをUnicodeとして保存するように要求します。その後、ファイルはUTF-8としてエンコードされます。これは、すべての非ASCII文字(コードページにあるものを含む)が2バイト以上で表されることを意味します。つまり、ソースを他の人に渡した場合、ソースは同じに見えます。ただし、ソースをコンパイラに渡す前に、VSはUTF-8でエンコードされたテキストをコードページでエンコードされたテキストに変換し、コードページで欠落している文字はすべてに置き換えられ?ます。

VSでUnicode文字列リテラルを正しく表すことを保証する唯一の方法は、文字列リテラルの前にLワイド文字列リテラルにすることです。この場合、VSはUTF-8でエンコードされたテキストをファイルからUCS2に変換します。次に、この文字列リテラルをstd::wstringコンストラクタに渡すか、それをutf-8に変換してに配置する必要がありますstd::string。または、Windows API関数を使用して、コードページを使用してエンコードし、それをに配置std::stringできますが、ワイド文字列リテラルを使用していない場合もあります。

std :: cout

使用してコンソールに出力するとき<<だけ使用することができstd::stringない、std::wstringそしてテキストがロケールのコードページを使用してエンコードする必要があります。がある場合std::wstringは、Windows API関数のいずれかを使用して変換する必要があり、コードページにない文字は置き換えられます?(多分、文字を変更できるので、覚えていません)。

std :: fstreamファイル名

Windows OSはファイル名にUCS2 / UTF-16を使用するため、コードページが何であれ、任意のUnicode文字のファイルを作成できます。ただし、これは、コードページにない文字でファイルにアクセスまたは作成するには、を使用する必要があることを意味しますstd::wstring。他に方法はありません。これはMicrosoft固有の拡張機能であるstd::fstreamため、おそらく他のシステムではコンパイルできません。std :: stringを使用する場合、コードページに文字のみを含むファイル名のみを使用できます。

あなたのオプション

Linuxで作業しているだけなら、おそらくここまで来ていません。std::stringどこでもUTF-8を使用するだけです。

Windowsだけで作業している場合は、std::wstringどこでもUCS2を使用してください。一部の純粋主義者は、UTF8を使用し、必要に応じて変換すると言うかもしれません。

あなたがクロスプラットフォームであるなら、それは率直に言うと混乱です。Windowsのあらゆる場所でUTF-8を使用する場合は、文字列リテラルとコンソールへの出力に十分注意する必要があります。そこの文字列は簡単に破損する可能性があります。std::wstringLinuxのどこでも使用している場合は、ワイドバージョンのにアクセスできない可能性があるstd::fstreamため、変換を行う必要がありますが、破損のリスクはありません。個人的には、これがより良いオプションだと思います。多くの人が反対するでしょうが、私は一人ではありません-それは、たとえばwxWidgetsがたどる経路です。

別のオプションは、LinuxとWindowsの場合とunicodestring同様std::stringにtypedef std::wstringであり、UNI()と呼ばれるマクロをWindowsでLの接頭辞付きにし、Linuxで何もない場合、次にコード

#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>

#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
    std::string result;
    //Call WideCharToMultiByte to do the conversion
    return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
    return str;
}
#endif

int main()
{

    unicodestring fileName(UNI("fileName"));
    std::ofstream fout;
    fout.open(fileName);
    std::cout << formatForConsole(fileName) << std::endl;
    return 0;
}

どちらのプラットフォームでも問題ないと思います。

答え

だからあなたの質問に答えるために

1)Windows用にプログラミングしている場合、Windowsで起こり得る破損の問題に対処したり#ifdefs、違いを回避するためにプラットフォーム固有のコードを記述したりしない限り、常に、クロスプラットフォームの場合はおそらく常にLinuxはそれから決して。

2)はい。さらにLinuxでは、すべてのUnicodeにも使用できます。Windowsでは、UTF-8を使用して手動でエンコードすることを選択した場合にのみ、すべてのUnicodeに使用できます。ただし、Windows APIと標準C ++クラスはstd::string、がロケールコードページを使用してエンコードされることを想定しています。これには、すべてのASCIIと、コンピュータが使用するように設定されているコードページに応じて変わる128文字が含まれます。

3)私はそう信じていますが、そうでない場合は、wchar_t代わりに使用する 'std :: basic_string'の単純なtypedef ですchar

4)ワイド文字は、1バイトの標準charタイプよりも大きい文字タイプです。Windowsでは2バイト、Linuxでは4バイトです。


1
「しかし、ソースをコンパイラに渡す前に、VSはUTF-8エンコードされたテキストをコードページエンコードされたテキストに変換し、コードページにない文字は?に置き換えられます。」->コンパイラがUTF-8エンコーディングを使用している場合(これはを使用/utf-8)には当てはまりません。
Roi Danton

私はこれをオプションとして認識していませんでした。このリンクdocs.microsoft.com/en-us/cpp/build/reference/…から、プロジェクトのプロパティで選択するチェックボックスがないようです。追加のコマンドラインオプションとして追加する必要があります。良いスポット!
Phil Rosenberg、


-6

ワイド文字を使用すべきでないのはいつですか?

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

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


16
@dave:私はUTF-8が作成する頭痛の種がわからない。これはWidechars(UTF-16)のそれよりも大きい。UTF-16では、複数文字の文字も使用できます。
Pavel Radzivilovsky、2009

問題は、英語圏以外の国にいる場合、wchar_tを使用する必要があることです。言うまでもなく、一部のアルファベットはバイトに収まらないほど多くの文字を持っています。私たちはDOSでそこにいた。コードページの統合失調症、いや、おかげで、これ以上の...
スウィフト-金曜日パイ

1
@Swiftの問題wchar_tは、そのサイズと意味がOS固有であることです。古い問題を新しい問題と交換するだけです。一方、a charcharOSに関係なく(少なくとも類似のプラットフォームでは)。したがって、UTF-8を使用してすべてをcharsのシーケンスにパックし、そのようなシーケンス内で測定、インデックス付け、検索などを行うための標準的な方法なしで、C ++が私たちに完全に任せていることを嘆くだけでもよいでしょう。
underscore_d 2017年

1
@スイフトあなたはそれを完全に後方に持っているようです。wchar_tは固定幅データ型であるため、10の配列wchar_tは常にsizeof(wchar_t) * 10プラットフォームバイトを占有します。また、UTF-16は可変幅エンコーディングで、文字は1つまたは2つの16ビットコードポイント(およびUTF-8の場合はs / 16/8 / g)で構成されます。
underscore_d 2017年

1
ウィンドウ上の@SteveHollasch wchar_t表現の文字列は、FFFFより大きい文字を特別なサロゲートペアとしてエンコードし、他の文字列は1つのwchar_t要素のみを受け取ります。そのため、その表現は、gnuコンパイラーによって作成された表現と互換性がありません(FFFF未満のすべての文字の前にゼロワードがあります)。何のwchar_tに格納されてすることはなく、いくつかの合意により、プログラマとコンパイラによって決定されます
スウィフト-金曜日パイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.