Frage Was ist mit C ++ wchar_t und wstrings "falsch"? Was sind einige Alternativen zu breiten Zeichen?


Ich habe viele Leute in der C ++ - Community (insbesondere ## c ++ auf freenode) gesehen, die die Verwendung von wstrings und wchar_tund ihre Verwendung in der Windows-API. Was ist genau "falsch" mit wchar_t und wstring, und wenn ich die Internationalisierung unterstützen möchte, welche Alternativen gibt es für breite Charaktere?


76
2018-06-19 19:00


Ursprung


Antworten:


Was ist wchar_t?

wchar_t ist so definiert, dass die char-Codierung eines Gebietsschemas in eine wchar_t-Darstellung konvertiert werden kann, wobei jedes wchar_t genau einen Codepunkt darstellt:

Typ wchar_t ist ein eindeutiger Typ, dessen Werte unterschiedliche Codes für alle Elemente des größten erweiterten Zeichensatzes darstellen können, der unter den unterstützten Locales (22.3.1) angegeben ist.

- C ++ [grundlegend.fundamental] 3.9.1 / 5

Dies nicht Erfordert, dass wchar_t groß genug ist, um ein beliebiges Zeichen aus allen Locales gleichzeitig darzustellen. Das heißt, die Codierung, die für wchar_t verwendet wird, unterscheidet sich möglicherweise zwischen den Gebietsschemas. Das bedeutet, dass Sie eine Zeichenfolge nicht unbedingt in wchar_t mit einem Gebietsschema konvertieren und dann mit einem anderen Gebietsschema wieder in ein Zeichen konvertieren können.1

Da die Verwendung von wchar_t als allgemeine Repräsentation zwischen allen Gebietsschemas die primäre Verwendung für wchar_t in der Praxis zu sein scheint, könnten Sie sich fragen, wofür es gut ist, wenn nicht.

Die ursprüngliche Absicht und der Zweck von wchar_t bestand darin, die Textverarbeitung so einfach zu machen, dass sie eine Eins-zu-Eins-Zuordnung von den Code-Einheiten eines Strings zu den Zeichen des Texts erfordert, wodurch dieselben einfachen Algorithmen wie verwendet verwendet werden können mit ASCII-Zeichenfolgen, um mit anderen Sprachen zu arbeiten.

Leider setzt der Wortlaut von wchar_ts Spezifikation eine Eins-zu-eins-Zuordnung zwischen Zeichen und Codepunkten voraus, um dies zu erreichen. Unicode bricht diese Annahme2, so dass wchar_t auch für einfache Textalgorithmen nicht sicher verwendet werden kann.

Dies bedeutet, dass portierbare Software wchar_t weder als allgemeine Repräsentation für Text zwischen Gebietsschemas verwenden noch die Verwendung einfacher Textalgorithmen ermöglichen kann.

Welchen Nutzen hat wchar_t heute?

Nicht viel, für tragbaren Code sowieso. Ob __STDC_ISO_10646__ Ist definiert, dann repräsentieren Werte von wchar_t direkt Unicode-Codepunkte mit den gleichen Werten in allen Locales. Das macht es sicher, die inter-locale Konvertierungen durchzuführen, die zuvor erwähnt werden. Sie können sich jedoch nicht darauf verlassen, dass Sie wchar_t auf diese Weise verwenden können, da Windows zwar die meisten Unix-Plattformen definiert, Windows jedoch nicht das gleiche wchar_t-Gebietsschema in allen Gebietsschemas verwendet.

Der Grund, warum Windows nicht definiert __STDC_ISO_10646__ ist, weil Windows UTF-16 als seine wchar_t-Codierung verwendet, und weil UTF-16 Ersatzpaare verwendet, um Codepunkte größer als U + FFFF darzustellen, was bedeutet, dass UTF-16 die Anforderungen für nicht erfüllt __STDC_ISO_10646__.

Für plattformspezifischen Code kann wchar_t hilfreicher sein. Es ist im Wesentlichen erforderlich unter Windows (z. B. können einige Dateien einfach nicht ohne wchar_t Dateinamen geöffnet werden), obwohl Windows die einzige Plattform ist, wo dies soweit ich weiß (also können wir vielleicht wchar_t als 'Windows_char_t' denken).

Im Nachhinein ist wchar_t offensichtlich nicht zur Vereinfachung der Textverarbeitung oder als Speicher für Gebietsschema-unabhängigen Text nützlich. Portabler Code sollte nicht versuchen, ihn für diese Zwecke zu verwenden. Nicht portierbarer Code kann nützlich sein, weil eine API es erfordert.

Alternativen

Die Alternative, die ich mag, ist die Verwendung von UTF-8-codierten C-Strings, auch auf Plattformen, die nicht besonders freundlich zu UTF-8 sind.

Auf diese Weise kann man portablen Code unter Verwendung einer gemeinsamen Textdarstellung plattformübergreifend schreiben, Standarddatentypen für den beabsichtigten Zweck verwenden, die Unterstützung der Sprache für diese Typen erhalten (z. B. Zeichenkettenliterale, einige Tricks sind notwendig, damit einige Compiler funktionieren) Unterstützung von Standard-Bibliotheken, Debugger-Unterstützung (möglicherweise sind mehr Tricks erforderlich) usw. Bei großen Zeichen ist es im Allgemeinen schwieriger oder unmöglich, all dies zu erhalten, und Sie können verschiedene Teile auf verschiedenen Plattformen erhalten.

Eine Sache, die UTF-8 nicht bietet, ist die Möglichkeit, einfache Textalgorithmen zu verwenden, wie sie mit ASCII möglich sind. In diesem UTF-8 ist nicht schlechter als jede andere Unicode-Codierung. In der Tat kann es als besser angesehen werden, da Multi-Code-Unit-Repräsentationen in UTF-8 häufiger vorkommen und somit Fehler im Code-Handling mit variabler Breite von Zeichen wahrscheinlicher bemerkt und behoben werden, als wenn Sie versuchen, bei UTF zu bleiben -32 mit NFC oder NFKC.

Viele Plattformen verwenden UTF-8 als native Zeichencodierung, und viele Programme erfordern keine wesentliche Textverarbeitung. Daher unterscheidet sich das Schreiben eines internationalisierten Programms auf diesen Plattformen kaum vom Schreiben von Code ohne Berücksichtigung der Internationalisierung. Das Schreiben weit verbreiteten Codes oder das Schreiben auf anderen Plattformen erfordert das Einfügen von Konvertierungen an den Grenzen von APIs, die andere Codierungen verwenden.

Eine andere Alternative, die von einer Software verwendet wird, ist die Auswahl einer plattformübergreifenden Repräsentation, wie z. B. unsignierte, kurze Arrays, die UTF-16-Daten enthalten, und dann die gesamte Bibliotheksunterstützung und einfach die Kosten für Sprachunterstützung usw.

C ++ 11 fügt neue Arten von breiten Zeichen als Alternativen zu wchar_t, char16_t und char32_t mit begleitenden Sprach- / Bibliotheksfunktionen hinzu. Diese sind nicht wirklich UTF-16 und UTF-32, aber ich kann mir nicht vorstellen, dass irgendeine größere Implementierung irgendetwas anderes verwenden wird. C ++ 11 verbessert auch die UTF-8-Unterstützung, zum Beispiel mit UTF-8-Zeichenfolgenliteralen, so dass es nicht notwendig ist, VC ++ zum Erzeugen von UTF-8-codierten Zeichenfolgen auszutricksen (obwohl ich dies weiterhin tun kann) u8 Präfix).

Alternativen zu vermeiden

TCHAR: TCHAR ist für die Migration von alten Windows-Programmen, die Legacy-Kodierungen von Char zu wchar_t annehmen, und ist am besten vergessen, es sei denn, Ihr Programm wurde in einem früheren Jahrtausend geschrieben. Es ist nicht portierbar und von Natur aus unspezifisch in Bezug auf seine Kodierung und sogar seinen Datentyp, wodurch es mit jeder nicht TCHAR-basierten API unbrauchbar wird. Da der Zweck der Migration zu wchar_t ist, was wir oben gesehen haben, ist keine gute Idee, es gibt keinen Wert in der Verwendung von TCHAR.


1. Zeichen, die in Zeichenketten wchar_t darstellbar sind, die aber in keinem Gebietsschema unterstützt werden, müssen nicht mit einem einzelnen wchar_t-Wert dargestellt werden. Das bedeutet, dass wchar_t für bestimmte Zeichen eine Codierung mit variabler Breite verwenden kann, was wiederum eine klare Verletzung der Absicht von wchar_t darstellt. Es kann zwar argumentiert werden, dass ein Zeichen, das durch wchar_t darstellbar ist, ausreicht, um zu sagen, dass das Gebietsschema dieses Zeichen "unterstützt". In diesem Fall sind Kodierungen mit variabler Breite nicht zulässig, und die Verwendung von UTF-16 durch Windows ist nicht konform.

2. Unicode ermöglicht die Darstellung vieler Zeichen mit mehreren Codepunkten, wodurch für einfache Textalgorithmen dieselben Probleme entstehen wie für Codierungen mit variabler Breite. Selbst wenn man eine zusammengesetzte Normalisierung strikt unterhält, benötigen einige Zeichen immer noch mehrere Codepunkte. Sehen: http://www.unicode.org/standard/where/


106
2018-06-25 21:52



Es gibt nichts "falsches" mit wchar_t. Das Problem ist, dass Microsoft in Microsoft Windows NT 3.x entschied, dass Unicode "Good" war und Unicode als 16-Bit-Zeichen "wchar_t" implementierte. Die meisten Microsoft-Literaturen aus der Mitte der 90er Jahre waren also ziemlich gleichgesetzt mit Unicode == utf16 == wchar_t.

Was leider nicht der Fall ist. "Weite Zeichen" sind nicht unbedingt 2 Bytes, auf allen Plattformen, unter allen Umständen.

Dies ist einer der besten Primer auf "Unicode" (unabhängig von dieser Frage, unabhängig von C ++), die ich je gesehen habe: Ich höchst empfiehl es:

Und ich glaube aufrichtig, dass der beste Weg, um mit "8-bit ASCII" vs "Win32 wide characters" gegenüber "wchar_t-in-general" umzugehen, einfach ist, "Windows is Different" zu akzeptieren ... und entsprechend zu codieren.

MEINER BESCHEIDENEN MEINUNG NACH...

PS:

Ich stimme jamesdlin zu:

Unter Windows haben Sie nicht wirklich eine Wahl. Seine internen APIs waren   entworfen für UCS-2, das war zu der Zeit vernünftig, seitdem es war   vor den UTF-8- und UTF-16-Kodierungen mit variabler Länge waren   standardisiert. Aber jetzt, wo sie UTF-16 unterstützen, haben sie es geschafft   das Schlimmste aus beiden Welten.


16
2018-06-19 23:39



Pflichtlektüre:

Das absolute Minimum, das jeder Softwareentwickler unbedingt und unbedingt über Unicode und Zeichensätze wissen muss (keine Ausreden!)

Wenn Sie Java oder .Net (VB.Net oder C #) programmieren, ist das weitgehend kein Problem: Beide sind standardmäßig Unicode. Wenn Sie in der "klassischen" Win32-API programmieren, ist Ihre beste Wette wahrscheinlich, TCHAR- und _T () - Makros zu verwenden (anstatt wchar explizit zu verwenden).

Alle Microsoft-Compiler VS2005 und höher, glaube ich, sind sowieso auf 16-Bit für C / C ++ voreingestellt (Teil des Grundes, warum ich immer noch MSVS 6.0 verwende, wann immer ich kann;)).

Ein anderer guter (wenn auch etwas veralteter) Link:


-4