wake-up-neo.com

std :: wstring VS std :: string

Ich kann die Unterschiede zwischen std::string und std::wstring nicht verstehen. Ich weiß, dass wstring breite Zeichen wie Unicode-Zeichen unterstützt. Ich habe folgende Fragen:

  1. Wann sollte ich std::wstring über std::string verwenden?
  2. Kann std::string den gesamten ASCII - Zeichensatz einschließlich der Sonderzeichen enthalten?
  3. Wird std::wstring von allen gängigen C++ - Compilern unterstützt?
  4. Was ist genau ein " breites Zeichen "?
673
Appu

string? wstring?

_std::string_ ist ein basic_string Template für ein char und _std::wstring_ für ein wchar_t .

char vs. _wchar_t_

char soll ein Zeichen enthalten, normalerweise ein 8-Bit-Zeichen.
_wchar_t_ soll einen breiten Charakter haben, und dann wird es schwierig:
Unter Linux ist ein _wchar_t_ 4 Bytes, während es unter Windows 2 Bytes sind.

Was ist dann mit nicode ?

Das Problem ist, dass weder char noch _wchar_t_ direkt an Unicode gebunden sind.

Unter Linux?

Nehmen wir ein Linux-Betriebssystem: Mein Ubuntu-System ist bereits Unicode-fähig. Wenn ich mit einer Zeichenfolge arbeite, wird diese nativ in TF-8 (d. H. Unicode-Zeichenfolge) codiert. Der folgende Code:

_#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;
}
_

gibt folgenden Text aus:

_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
_

Sie werden sehen, dass der Text "olé" in char wirklich aus vier Zeichen besteht: 110, 108, 195 und 169 (ohne die nachgestellte Null). (Ich lasse Sie den _wchar_t_ Code als Übung studieren.)

Wenn Sie also unter Linux mit einem char arbeiten, sollten Sie in der Regel Unicode verwenden, ohne es überhaupt zu wissen. Und da _std::string_ mit char zusammenarbeitet, ist _std::string_ bereits Unicode-fähig.

Beachten Sie, dass _std::string_ wie die C-String-API den "olé" -String mit 4 Zeichen und nicht mit drei Zeichen betrachtet. Sie sollten also vorsichtig sein, wenn Sie mit Unicode-Zeichen kürzen/spielen, da eine Kombination von Zeichen in UTF-8 verboten ist.

Unter Windows?

Unter Windows ist das etwas anders. Win32 musste eine Menge Anwendungen unterstützen, die mit char und auf verschiedenen Zeichensätzen / Codepages , die auf der ganzen Welt produziert wurden, vor dem Aufkommen von Unicode arbeiten.

Ihre Lösung war daher interessant: Wenn eine Anwendung mit char arbeitet, werden die Zeichenfolgen unter Verwendung des lokalen Zeichensatzes/der Codepage auf dem Computer auf GUI-Etiketten codiert/gedruckt/angezeigt. Zum Beispiel wäre "olé" in einem französischsprachigen Windows "olé", in einem kyrillischsprachigen Windows jedoch etwas anderes ("olé", wenn Sie Windows-1251 ). Somit funktionieren "historische Apps" normalerweise immer noch auf die gleiche Weise.

Für Unicode-basierte Anwendungen verwendet Windows _wchar_t_, das 2 Byte breit und in TF-16 codiert ist, was Unicode-Codierung für 2-Byte-Zeichen (oder zumindest) bedeutet , das meist kompatible UCS-2, das ist fast dasselbe (IIRC).

Anwendungen, die char verwenden, werden als "Multibyte" bezeichnet (da jede Glyphe aus einem oder mehreren chars besteht), während Anwendungen, die _wchar_t_ verwenden, als "widechar" bezeichnet werden (weil jede Glyphe aus einem besteht) oder zwei _wchar_t_. Weitere Informationen finden Sie unter MultiByteToWideChar und WideCharToMultiByte Win32-Konvertierungs-API.

Wenn Sie also unter Windows arbeiten, möchten Sie unbedingt _wchar_t_ verwenden (es sei denn, Sie verwenden ein Framework, das dies verbirgt, wie GTK + oder QT ...). Tatsache ist, dass Windows hinter den Kulissen mit _wchar_t_ Zeichenfolgen arbeitet, sodass selbst bei historischen Anwendungen die char Zeichenfolgen in _wchar_t_ konvertiert werden, wenn eine API wie SetWindowText() (niedrige Stufe) verwendet wird API-Funktion zum Festlegen der Bezeichnung auf einer Win32-Benutzeroberfläche.

Speicherprobleme?

UTF-32 besteht aus 4 Bytes pro Zeichen. Es muss also nicht viel hinzugefügt werden, wenn nur ein UTF-8-Text und ein UTF-16-Text immer weniger oder denselben Speicherplatz belegen wie ein UTF-32-Text (und in der Regel weniger) ).

Wenn es ein Speicherproblem gibt, sollten Sie wissen, dass UTF-8-Text für die meisten westlichen Sprachen weniger Speicher benötigt als derselbe UTF-16-Text.

Für andere Sprachen (Chinesisch, Japanisch usw.) ist der verwendete Speicher für UTF-8 entweder derselbe oder geringfügig größer als für UTF-16.

Alles in allem verwendet UTF-16 meistens 2 und gelegentlich 4 Bytes pro Zeichen (es sei denn, es handelt sich um eine Art esoterischer Sprachglyphen (klingonisch? Elfisch?), Während UTF-8 1 bis 4 Bytes ausgibt.

Siehe http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 für weitere Informationen.

Fazit

  1. Wann sollte ich std :: wstring über std :: string setzen?

    Unter Linux? Fast nie (§).
    Unter Windows? Fast immer (§).
    Auf plattformübergreifendem Code? Kommt auf dein Toolkit an ...

    (§): sofern Sie kein anderes Toolkit/Framework verwenden

  2. Kann _std::string_ den gesamten Zeichensatz ASCII einschließlich Sonderzeichen enthalten?

    Hinweis: Ein _std::string_ eignet sich zum Speichern eines 'binären' Puffers, ein _std::wstring_ dagegen nicht!

    Unter Linux? Ja.
    Unter Windows? Für das aktuelle Gebietsschema des Windows-Benutzers sind nur Sonderzeichen verfügbar.

    Bearbeiten (Nach einem Kommentar von Johann Gerell ):
    a _std::string_ reicht aus, um alle char -basierten Zeichenfolgen zu verarbeiten (wobei jede char eine Zahl von 0 bis 255 ist). Aber:

    1. ASCII soll von 0 bis 127 gehen. Höhere chars sind NICHT ASCII.
    2. ein char von 0 bis 127 wird korrekt gespeichert
    3. a char von 128 bis 255 hat eine von Ihrer Codierung abhängige Bedeutung (Unicode, Nicht-Unicode usw.), kann jedoch alle Unicode-Glyphen speichern, solange sie in UTF-8 codiert sind.
  3. Wird _std::wstring_ von fast allen gängigen C++ - Compilern unterstützt?

    Meistens mit Ausnahme von GCC-basierten Compilern, die auf Windows portiert sind.
    Es funktioniert auf meinem g ++ 4.3.2 (unter Linux) und ich habe Unicode API unter Win32 seit Visual C++ 6 verwendet.

  4. Was ist genau ein breites Zeichen?

    In C/C++ handelt es sich um einen geschriebenen Zeichentyp _wchar_t_, der größer ist als der einfache Zeichentyp char. Hiermit sollen Zeichen eingefügt werden, deren Indizes (wie Unicode-Glyphen) größer als 255 sind (oder 127, abhängig von ...).

955
paercebal

Ich empfehle, std::wstring unter Windows oder anderswo zu vermeiden, es sei denn, dies wird von der Benutzeroberfläche verlangt oder in der Nähe von Windows-API-Aufrufen und entsprechenden Codierungskonvertierungen als syntaktischer Zucker. 

Meine Ansicht ist in http://utf8everywhere.org zusammengefasst, von der ich Mitautor bin. 

Wenn Ihre Anwendung nicht auf API-Aufrufe ausgerichtet ist, z. Im Wesentlichen handelt es sich um eine UI-Anwendung. Der Vorschlag besteht darin, Unicode-Zeichenfolgen in std :: string zu speichern und in UTF-8 zu codieren, um eine Konvertierung in der Nähe von API-Aufrufen durchzuführen. Die in diesem Artikel beschriebenen Vorteile überwiegen die offensichtliche Belästigung der Konvertierung, insbesondere bei komplexen Anwendungen. Dies gilt doppelt für die Entwicklung von Plattformen und Bibliotheken. 

Und jetzt beantworte ich deine Fragen:

  1. Ein paar schwache Gründe. Es gibt es aus historischen Gründen, in denen geglaubt wurde, dass Widechars der richtige Weg sei, Unicode zu unterstützen. Jetzt werden APIs verwendet, die UTF-16-Strings bevorzugen. Ich verwende sie nur in unmittelbarer Nähe solcher API-Aufrufe.
  2. Das hat nichts mit std :: string zu tun. Es kann die Kodierung enthalten, die Sie darin einfügen. Die Frage ist nur, wie You den Inhalt behandelt. Meine Empfehlung ist UTF-8, daher können alle Unicode-Zeichen korrekt gespeichert werden. Es ist eine übliche Praxis unter Linux, aber ich denke, Windows-Programme sollten es auch tun.
  3. Nein. 
  4. Breites Zeichen ist ein verwirrender Name. In den Anfängen von Unicode wurde davon ausgegangen, dass ein Zeichen in zwei Bytes codiert werden kann, daher der Name. Heute steht es für "jeden Teil des Zeichens, der zwei Byte lang ist". UTF-16 wird als eine Folge solcher Byte-Paare (auch als Wide-Zeichen bezeichnet) verstanden. Ein Zeichen in UTF-16 benötigt ein oder zwei Paare.
54

Daher sollte jeder Leser hier ein klares Verständnis der Fakten und der Situation haben. Wenn nicht, dann Sie müssen die hervorragend umfassende Antwort von Paercebal lesen [btw: danke!].

Meine pragmatische Schlussfolgerung ist erschreckend einfach: Alles, was mit C++ (und STL) "Zeichenkodierung" zu tun hat, ist im Wesentlichen kaputt und nutzlos. Schuld an Microsoft oder nicht, das wird sowieso nicht helfen.

Meine Lösung nach eingehender Untersuchung, viel Frustration und den daraus folgenden Erfahrungen ist folgende:

  1. akzeptieren Sie, dass Sie selbst für die Kodierung und Konvertierung verantwortlich sein müssen (und Sie werden feststellen, dass vieles davon ziemlich trivial ist)

  2. verwenden Sie std :: string für beliebige UTF-8-codierte Zeichenfolgen (nur ein typedef std::string UTF8String).

  3. akzeptieren Sie, dass ein solches UTF8String-Objekt nur ein dummer, aber billiger Container ist. Greifen Sie niemals direkt auf Zeichen darin zu und/oder manipulieren Sie sie nicht (Suchen, Ersetzen usw.). Sie könnten, aber Sie wollen wirklich keine Zeit damit verschwenden, Textbearbeitungsalgorithmen für Multi-Byte-Strings zu schreiben! Selbst wenn andere Leute schon so dumme Sachen gemacht haben, tun Sie das nicht! Kümmer dich nicht darum! (Nun, es gibt Szenarien, in denen es sinnvoll ist ... verwenden Sie einfach die Bibliothek ICU).

  4. verwenden Sie std :: wstring für UCS-2-codierte Zeichenfolgen (typedef std::wstring UCS2String). Dies ist ein Kompromiss und eine Zugeständnis für das Durcheinander, das die WIN32-API eingeführt hat. UCS-2 ist für die meisten von uns ausreichend (dazu später mehr ...).

  5. verwenden Sie UCS2String-Instanzen, wenn ein zeichenweiser Zugriff erforderlich ist (Lesen, Bearbeiten usw.). Jede zeichenbasierte Verarbeitung sollte in einer NICHT-Multibyte-Darstellung erfolgen. Es ist einfach, schnell und einfach.

  6. fügen Sie zwei Utility-Funktionen hinzu, um zwischen UTF-8 und UCS-2 hin und her zu konvertieren:

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

Die Konvertierungen sind unkompliziert, Google sollte hier helfen ...

Das ist es. Verwenden Sie UTF8String überall dort, wo Speicher wichtig ist, und für alle UTF-8-E/A. Verwenden Sie UCS2String überall dort, wo der String analysiert und/oder bearbeitet werden muss. Sie können jederzeit zwischen diesen beiden Darstellungen konvertieren.

Alternativen & Verbesserungen

  • umwandlungen von & in Einzelbyte-Zeichencodierungen (z. B. ISO-8859-1) können mit Hilfe einfacher Übersetzungstabellen, z. const wchar_t tt_iso88951[256] = {0,1,2,...}; und entsprechender Code für die Konvertierung in & von UCS2.

  • wenn UCS-2 nicht ausreicht, dann zu UCS-4 wechseln (typedef std::basic_string<uint32_t> UCS2String)

ICU oder andere Unicode-Bibliotheken?

Für Fortgeschrittene.

36
Frunsi
  1. Wenn Sie breite Zeichen in Ihrer Zeichenfolge speichern möchten. wide hängt von der Implementierung ab. Wenn ich mich richtig erinnere, ist Visual C++ auf 16 Bit voreingestellt, während GCC abhängig vom Ziel vorgegeben ist. Es ist hier 32 Bit lang. Bitte beachten Sie, dass wchar_t (Wide Character Type) nichts mit Unicode zu tun hat. Es ist lediglich garantiert, dass alle Mitglieder des größten Zeichensatzes gespeichert werden können, den die Implementierung von ihren Gebietsschemas unterstützt, und zwar mindestens so lange wie char. Sie können store Unicode-Strings auch in std::string verwenden, indem Sie auch die utf-8-Kodierung verwenden. Es versteht jedoch nicht die Bedeutung von Unicode-Codepunkten. Daher gibt str.size() nicht die Anzahl der logischen Zeichen in Ihrer Zeichenfolge an, sondern lediglich die Anzahl der char- oder wchar_t-Elemente, die in dieser Zeichenfolge/Zeichenfolge gespeichert sind. Aus diesem Grund haben die C++ - Wrapper-Leute von gtk/glib eine Glib::ustring -Klasse entwickelt, die utf-8 verarbeiten kann. 

    Wenn Ihr wchar_t 32 Bit lang ist, können Sie utf-32 als Unicode-Kodierung verwenden und Sie können und Unicode-Strings mit einer festen Kodierung (utf-32 ist feste Länge) speichern. Dies bedeutet, dass die Funktion s.size() des Wstrings dann die richtige Menge der wchar_t-Elemente und zurückgibt. 

  2. Ja, char ist immer mindestens 8 Bit lang, dh es können alle ASCII - Werte gespeichert werden. 
  3. Ja, alle großen Compiler unterstützen es.

Ich verwende häufig std :: string, um utf-8-Zeichen problemlos zu halten. Ich empfehle Ihnen dies in Verbindung mit APIs, die utf-8 als nativen Zeichenfolgentyp verwenden.

Zum Beispiel verwende ich utf-8, wenn ich meinen Code mit dem Tcl-Interpreter verbinde.

Der Hauptvorbehalt ist die Länge der std :: Zeichenfolge, nicht mehr die Anzahl der Zeichen in der Zeichenfolge.

5
Juan
  1. Wenn Sie 'Wide'-Zeichen (Unicode) speichern möchten.
  2. Ja: 255 davon (außer 0).
  3. Ja.
  4. Hier ist ein einleitender Artikel: http://www.joelonsoftware.com/articles/Unicode.html
3
ChrisW

Anwendungen, die nicht mit nur 256 verschiedenen Zeichen zufrieden sind, können entweder breite Zeichen (mehr als 8 Bit) oder eine Kodierung mit variabler Länge (eine Multibyte-Kodierung in C++ - Terminologie) wie UTF-8 verwenden. Breite Zeichen erfordern im Allgemeinen mehr Platz als eine Kodierung mit variabler Länge, sind jedoch schneller zu verarbeiten. Mehrsprachige Anwendungen, die große Mengen an Text verarbeiten, verwenden normalerweise breite Zeichen, wenn sie den Text verarbeiten, konvertieren ihn jedoch in UTF-8, wenn er auf Festplatte gespeichert wird.

Der einzige Unterschied zwischen einer string und einer wstring ist der Datentyp der Zeichen, die sie speichern. Ein String speichert chars, deren Größe mindestens 8 Bit beträgt. Sie können also Strings für die Verarbeitung verwenden, z. ASCII-, ISO-8859-15- oder UTF-8-Text. Der Standard sagt nichts über den Zeichensatz oder die Kodierung aus.

Praktisch jeder Compiler verwendet einen Zeichensatz, dessen erste 128 Zeichen mit ASCII übereinstimmen. Dies ist auch bei Compilern der Fall, die die UTF-8-Codierung verwenden. Beachten Sie bei der Verwendung von Zeichenfolgen in UTF-8 oder einer anderen Codierung mit variabler Länge, dass die Indizes und Längen in Byte und nicht in Zeichen gemessen werden.

Der Datentyp eines Wstrings ist wchar_t, dessen Größe im Standard nicht definiert ist, mit der Ausnahme, dass er mindestens so groß wie ein Zeichen sein muss, normalerweise 16 Bit oder 32 Bit. wstring kann für die Verarbeitung von Text in der implementierten Wide-Character-Codierung verwendet werden. Da die Kodierung im Standard nicht definiert ist, ist das Konvertieren zwischen Strings und Wstrings nicht einfach. Man kann auch nicht davon ausgehen, dass Zeichenfolgen eine Kodierung mit fester Länge haben.

Wenn Sie keine Unterstützung für mehrere Sprachen benötigen, können Sie nur reguläre Zeichenfolgen verwenden. Wenn Sie dagegen eine grafische Anwendung schreiben, wird die API häufig nur Breitzeichen unterstützen. Dann möchten Sie wahrscheinlich die gleichen breiten Zeichen für die Verarbeitung des Textes verwenden. Denken Sie daran, dass UTF-16 eine Kodierung mit variabler Länge ist. Das bedeutet, dass Sie nicht annehmen können, dass length() die Anzahl der Zeichen zurückgibt. Wenn die API eine Codierung mit fester Länge wie UCS-2 verwendet, wird die Verarbeitung vereinfacht. Das Konvertieren zwischen breiten Zeichen und UTF-8 ist auf tragbare Weise schwierig durchzuführen, aber Ihre Benutzeroberflächen-API unterstützt die Konvertierung wahrscheinlich ebenfalls.

2
Seppo Enarvi
  1. wenn Sie Unicode-Zeichenfolgen verwenden möchten und nicht nur ASCII, ist dies für die Internationalisierung hilfreich
  2. ja, aber es spielt nicht gut mit 0
  3. ich weiß nicht, wer das nicht tut
  4. wide-Zeichen ist die compilerspezifische Methode zum Umgang mit der Darstellung fester Länge eines Unicode-Zeichens. Bei MSVC handelt es sich um ein 2-Byte-Zeichen. und ein +1 für http://www.joelonsoftware.com/articles/Unicode.html
1
Greg Domjan

1) Wie von Greg erwähnt, ist wstring hilfreich für die Internationalisierung. Dann werden Sie Ihr Produkt in anderen Sprachen als Englisch veröffentlichen

4) Überprüfen Sie das Breitzeichen http://en.wikipedia.org/wiki/Wide_character

0
Raghu

Eine gute Frage! Ich denke, DATA ENCODING (manchmal ist auch einCHARSETbeteiligt) ein MEMORY EXPRESSION MECHANISM, um Daten in eine Datei zu speichern oder Daten über eine Netzwerk, so beantworte ich diese Frage als:

1. Wann sollte ich std :: wstring über std :: string verwenden?

Wenn die Programmierplattform oder die API-Funktion eine Einzelbyte-Funktion ist und einige Unicode-Daten verarbeitet oder analysiert werden sollen, z. B. Lesen aus der Windows'REG-Datei oder einem 2-Byte-Stream im Netzwerk, sollten wir die Variable std :: wstring leicht deklarieren verarbeiten sie. Beispiel: wstring ws = L "a" (Speicher mit 6 Oktetten: 0x4E2D 0x56FD 0x0061), wir können ws [0] verwenden, um das Zeichen '中' und ws [1] das Zeichen '国' und ws [2] zu erhalten Holen Sie sich das Zeichen 'a' usw.

2. Kann std :: string den gesamten ASCII - Zeichensatz einschließlich der Sonderzeichen enthalten?

Ja. Beachten Sie jedoch: Amerikanisches ASCII bedeutet, dass jedes 0x00 ~ 0xFF-Oktett für ein Zeichen steht, einschließlich druckfähigem Text wie "123abc & * _ &" und Sie sagten, dass ein spezielles, meist als "." Vermeiden Sie, die Redakteure oder Terminals zu verwirren. Und einige andere Länder erweitern ihren eigenen ASCII-Zeichensatz, z. Chinesisch, verwenden Sie 2 Oktetts, um für ein Zeichen zu stehen. 

3.Ist std :: wstring von allen gängigen C++ - Compilern unterstützt?

Vielleicht oder meistens. Ich habe verwendet: VC++ 6 und GCC 3.3, YES

4. Was ist genau ein "breites Zeichen"?

ein Breitzeichen bedeutet meistens, dass 2 Oktette oder 4 Oktette verwendet werden, um die Zeichen aller Länder aufzunehmen. 2 Oktett UCS2 ist eine repräsentative Probe und ferner z. Englisch 'a', sein Speicher ist 2 Oktett von 0x0061 (vs in ASCII 'a' s Speicher ist 1 Oktett 0x61)

0
Leiyi.China

Hier gibt es einige sehr gute Antworten, aber ich denke, es gibt einige Dinge, die ich in Bezug auf Windows/Visual Studio hinzufügen kann. Dies basiert auf meinen Erfahrungen mit VS2015. Unter Linux lautet die Antwort grundsätzlich, überall UTF-8-codiert std::string Zu verwenden. Unter Windows/VS wird es komplexer. Hier ist warum. Windows erwartet, dass Zeichenfolgen, die mit chars gespeichert wurden, mit der Codepage des Gebietsschemas codiert werden. Dies ist fast immer der Zeichensatz ASCII gefolgt von 128 weiteren Sonderzeichen, abhängig von Ihrem Standort. Lassen Sie mich nur sagen, dass dies nicht nur bei Verwendung der Windows-API der Fall ist, sondern es gibt drei weitere wichtige Stellen, an denen Diese Zeichenfolgen interagieren mit Standard-C++. Dies sind Zeichenfolgenliterale, die mit std::cout an << ausgegeben werden und einen Dateinamen an std::fstream übergeben.

Ich werde hier ganz vorne mit dabei sein, dass ich Programmierer und kein Sprachspezialist bin. Ich schätze, dass USC2 und UTF-16 nicht dasselbe sind, aber für meine Zwecke sind sie nah genug, um austauschbar zu sein, und ich verwende sie hier als solche. Ich bin mir nicht sicher, welches Windows verwendet wird, aber ich muss es im Allgemeinen auch nicht wissen. Ich habe UCS2 in dieser Antwort angegeben. Es tut mir im Voraus leid, wenn ich jemanden mit meiner Unkenntnis dieser Angelegenheit verärgert habe, und ich bin froh, sie zu ändern, wenn ich etwas falsch mache.

String-Literale

Wenn Sie Zeichenfolgenliterale eingeben, die nur Zeichen enthalten, die von Ihrer Codepage dargestellt werden können, speichert VS sie in Ihrer Datei mit 1 Byte pro Zeichencodierung basierend auf Ihrer Codepage. Beachten Sie, dass, wenn Sie Ihre Codepage ändern oder Ihre Quelle mit einer anderen Codepage an einen anderen Entwickler weitergeben, der Charakter meines Erachtens anders ausfällt (aber nicht getestet wurde). Wenn Sie Ihren Code auf einem Computer mit einer anderen Codepage ausführen, bin ich mir nicht sicher, ob sich auch das Zeichen ändert.

Wenn Sie Zeichenfolgenliterale eingeben, die von Ihrer Codepage nicht dargestellt werden können, fordert VS Sie auf, die Datei als Unicode zu speichern. Die Datei wird dann als UTF-8 codiert. Dies bedeutet, dass alle Nicht ASCII Zeichen (einschließlich der auf Ihrer Codepage)) durch 2 oder mehr Bytes dargestellt werden. Wenn Sie Ihre Quelle einer anderen Person geben, sieht die Quelle gleich aus Bevor jedoch die Quelle an den Compiler übergeben wird, konvertiert VS den UTF-8-codierten Text in Codepage-codierten Text und alle Zeichen, die auf der Codepage fehlen, werden durch ? Ersetzt.

Die einzige Möglichkeit, sicherzustellen, dass ein Unicode-Zeichenfolgenliteral in VS korrekt dargestellt wird, besteht darin, dem Zeichenfolgenliteral ein L voranzustellen und es zu einem breiten Zeichenfolgenliteral zu machen. In diesem Fall konvertiert VS den UTF-8-codierten Text aus der Datei in UCS2. Anschließend müssen Sie dieses Zeichenfolgenliteral an einen Konstruktor std::wstring Übergeben oder es in utf-8 konvertieren und in einen std::string Einfügen. Oder wenn Sie möchten, können Sie die Windows-API-Funktionen verwenden, um sie mit Ihrer Codepage zu codieren, um sie in einen std::string - Code zu setzen. Dann haben Sie möglicherweise auch kein breites Zeichenfolgenliteral verwendet.

std :: cout

Bei der Ausgabe an die Konsole mit << Können Sie nur std::string Und nicht std::wstring Verwenden, und der Text muss mit Ihrer Codepage für das Gebietsschema codiert werden. Wenn Sie einen std::wstring Haben, müssen Sie ihn mit einer der Windows-API-Funktionen konvertieren, und alle Zeichen, die nicht in Ihrer Codepage enthalten sind, werden durch ? Ersetzt (möglicherweise können Sie das Zeichen ändern, ich kann nicht) merken).

std :: fstream Dateinamen

Das Windows-Betriebssystem verwendet UCS2/UTF-16 als Dateinamen, sodass Sie unabhängig von Ihrer Codepage Dateien mit einem beliebigen Unicode-Zeichen haben können. Dies bedeutet jedoch, dass Sie zum Zugreifen auf oder Erstellen von Dateien mit Zeichen, die nicht in Ihrer Codepage enthalten sind, std::wstring Verwenden müssen. Es geht nicht anders. Dies ist eine Microsoft-spezifische Erweiterung für std::fstream, Die auf anderen Systemen wahrscheinlich nicht kompiliert werden kann. Wenn Sie std :: string verwenden, können Sie nur Dateinamen verwenden, die nur Zeichen auf Ihrer Codepage enthalten.

Deine Optionen

Wenn Sie nur unter Linux arbeiten, sind Sie wahrscheinlich nicht so weit gekommen. Verwenden Sie einfach UTF-8 std::string Überall.

Wenn Sie nur unter Windows arbeiten, verwenden Sie UCS2 std::wstring Überall. Einige Puristen sagen vielleicht, dass sie UTF8 verwenden und dann konvertieren, wenn es nötig ist, aber warum sollte man sich die Mühe machen?.

Wenn Sie plattformübergreifend sind, ist es ein Chaos, ehrlich zu sein. Wenn Sie versuchen, UTF-8 unter Windows überall zu verwenden, müssen Sie sehr vorsichtig mit Ihren String-Literalen umgehen und auf der Konsole ausgeben. Sie können Ihre Zeichenfolgen dort leicht beschädigen. Wenn Sie std::wstring Überall unter Linux verwenden, haben Sie möglicherweise keinen Zugriff auf die breite Version von std::fstream, Daher müssen Sie die Konvertierung durchführen, es besteht jedoch kein Korruptionsrisiko. Ich persönlich halte das für eine bessere Option. Viele würden dem nicht zustimmen, aber ich bin nicht allein - dies ist beispielsweise der Weg, den wxWidgets eingeschlagen hat.

Eine andere Möglichkeit könnte sein, unicodestring unter Linux als std::string Und unter Windows als std::wstring Zu tippen und ein Makro namens UNI () zu haben, das L unter Windows und dann nichts unter Linux voranstellt der Code

#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;
}

wäre in Ordnung auf beiden Plattformen, denke ich.

Antworten

So beantworten Sie Ihre Fragen

1) Wenn Sie für Windows programmieren, dann die ganze Zeit, wenn plattformübergreifend, dann vielleicht die ganze Zeit, es sei denn, Sie möchten sich mit möglichen Korruptionsproblemen unter Windows befassen oder einen Code mit plattformspezifischem #ifdefs Schreiben, um dies zu umgehen Die Unterschiede, wenn Sie nur Linux verwenden, dann nie.

2) ja Zusätzlich kann es unter Linux auch für alle Unicode-Versionen verwendet werden. Unter Windows können Sie es nur für alle Unicode-Dateien verwenden, wenn Sie sich für die manuelle Codierung mit UTF-8 entscheiden. Die Windows-API und die Standard-C++ - Klassen erwarten jedoch, dass std::string Mit der Codepage des Gebietsschemas codiert wird. Dies schließt alle ASCII plus weitere 128 Zeichen ein, die sich abhängig von der Codepage ändern, für die Ihr Computer eingerichtet ist.

3) Ich glaube schon, aber wenn nicht, dann ist es nur eine einfache Typdefinition eines 'std :: basic_string' mit wchar_t Anstelle von char

4) Ein Breitzeichen ist ein Zeichentyp, der größer als der 1-Byte-Standardtyp char ist. Unter Windows sind es 2 Bytes, unter Linux sind es 4 Bytes.

0
Phil Rosenberg