2009-07-04 10 views
11

Dies ist eine ANSI C Frage. Ich habe den folgenden Code.wchar_t vs wint_t

Ich brauche volle UTF-8-Unterstützung, aber kann ich dies auch auf dieser einfachsten Ebene irgendwie verbessern? Warum wird wint_t verwendet, und nicht wchar, mit entsprechenden Änderungen?

Antwort

3

UTF-8 ist eine mögliche Kodierung für Unicode. Es definiert 1, 2, 3 oder 4 Bytes pro Zeichen. Wenn Sie es durch getwc() lesen, wird es ein bis vier Bytes abrufen und daraus ein einzelnes Unicode-Zeichen Codepunkt, die in eine wchar passen würde (die 16 oder sogar 32 Bit breit sein können, je nach Plattform).

Da Unicode-Werte jedoch allen Werten von 0x0000 bis 0xFFFF zugeordnet sind, sind keine Werte für die Rückgabe von Bedingungen oder Fehlern vorhanden. (Einige haben darauf hingewiesen, dass Unicode größer als 16 Bits ist die Fälle surrogate pairs verwendet. Aber der Punkt ist, dass Unicode verwendet alle der verfügbaren Werte verlassen keine für EOF.)

diverse Fehlercodes umfassen EOF (WEOF), die auf -1 abbildet. Wenn Sie den Rückgabewert getwc() in eine wchar setzen würden, gäbe es keine Möglichkeit, sie von einem Unicode 0xFFFF Zeichen zu unterscheiden (das, BTW, ist sowieso reserviert, aber ich schweife ab).

So ist die Antwort einen breiteren Typen verwenden, ein wint_t (oder int), die mindestens 32 Bits enthält. Das gibt die unteren 16 Bits für den realen Wert, und alles mit einem außerhalb dieses Bereichs gesetzten Bit bedeutet, dass etwas anderes als ein zurückkehrendes Zeichen passiert ist.

Warum verwenden wir nicht immer wchar dann statt wint? Die meisten string-bezogenen Funktionen verwenden wchar, da sie auf den meisten Plattformen die halbe Größe von wint haben, so dass Strings einen kleineren Speicherbedarf haben.

+2

Ein UTF-8-Zeichen kann 4 Byte lang sein, technische es sogar 5 oder 6 Bytes nehmen, aber solche Zusammensetzungen sind nicht gültig UTF-8-Zeichen. – quinmars

+0

Nun, wahr. Es kann 4 Byte lang sein, wenn Sie die zusätzlichen Plan Zeichen von 0x10000 gehen und höher, aber das wird in Surrogate, wenn sie mit UTF-16 zu tun, und ich dachte, es nicht in den Anwendungsbereich der Frage. Und während 5 oder 6 Byte-Sequenzen möglich sind, können sie immer in weniger als 5 Bytes ausgedrückt werden und werden nur von Serializern schlechter Qualität erzeugt. – lavinio

+2

Ihre Antwort ist größtenteils korrekt, aber Sie liefern zu viele (platofrm depentent) Details. 'wchar_t' ist _nicht_ immer 16 Bits, ich kann mir mindestens 2 OS/Compiler-Kombinationen vorstellen, wo es 32 ist. –

15

wint_t kann jeden gültigen Wert von wchar_t speichern. A wint_t ist auch in der Lage, das Ergebnis der Auswertung des Makros WEOF zu übernehmen (beachten Sie, dass ein wchar_t zu schmal ist, um das Ergebnis zu halten).

+1

OK, thanks. Kurz gesagt: Wann ist es besser wchar_t zu benutzen? Warum nicht immer wint_t verwenden? –

+10

'wint_t' steht für' wchar_t' was 'int' für' char' ist. Wir verwenden keine Arrays von 'int's für schmale Strings, obwohl' getc() '' int' zurückgibt, um 'EOF' zurückgeben zu können. In ähnlicher Weise verwenden wir keine Arrays von 'wint_t's für breite Strings, obwohl' getwc() '' 'wint_t' zurückgibt, um' WEOF' zurückgeben zu können. – musiphil

+2

@musiphil: Dein Kommentar verdient es, eine Antwort zu sein, es ist die einzige, die über den * konzeptionellen * Unterschied zwischen ihnen spricht. – MestreLion

6

Als @musiphil so schön in seinem Kommentar legen, die ich hier zu erweitern versuchen würde, gibt es einen konzeptionellen Unterschied zwischen wint_t und wchar_t.

Ihre unterschiedlichen Größen sind ein technischer Aspekt, der sich aus der Tatsache ergibt sich jede Semantik sehr verschieden hat:

  • wchar_t groß genug ist, Zeichen speichern oder Codepoints wenn Sie bevorzugen. Als solche sind sie unsigned. Sie sind analog zu char, die in praktisch allen Plattformen auf 8-Bit-256-Werte beschränkt war. So Wide-Char-Zeichenfolgen Variablen sind natürlich Arrays oder Zeiger dieses Typs.

  • Geben Sie jetzt String Funktionen, einige davon müssen in der Lage, allewchar_t plus zusätzliche Status zurückzukehren. So ihr Rückgabetyp muss größer sein als wchar_t. So wird wint_t verwendet, das beliebige breite Zeichen ausdrücken kann und auch WEOF. Als ein Status, kann es auch sein negativ (und in der Regel ist), daher ist wint_t höchstwahrscheinlich unterzeichnet. Ich sage „möglicherweise“, weil der C-Standard nicht Mandat es zu sein. Aber unabhängig davon, Zeichen, müssen Statuswerte außerhalb der Bereich von wchar_t sein. Sie sind nur als Rückgabewerte nützlich und sollten niemals solche Zeichen enthalten.

Die Analogie mit „klassischen“ char und int großer Verwirrung zu klären ist: Strings sind nicht vom Typ int [], sie sind char var[] (oder char *var). Und nicht, weil charist "die halbe Größe von int", aber weil das ist, was eine Zeichenfolge ist.

Ihr Code sieht korrekt aus: c wird verwendet, um das Ergebnis getwch() zu überprüfen, also ist es wint_t. Und wenn sein Wert nicht WEOF ist, wie Ihre if Tests, dann ist es sicher, es einem wchar_t Zeichen (oder einem Zeichenfolgenarray, Zeiger, usw.) zuzuweisen

+1

Hmmmm nicht zustimmen: C11 Spec sagt, 'wint_t' kann signiert oder unsigniert sein. Weiter heißt es: "Der Wert des Makros, WEOF 'kann sich von, EOF' unterscheiden und muss nicht negativ sein." – chux

+2

@chux: fertig ... Ich hoffe, es ist jetzt verbessert, und danke für Hinweis – MestreLion

+2

'wchar_t' ist nicht unbedingt groß genug, um Codepunkte zu speichern. Insbesondere unter Windows sind es nur 16 Bits, was bedeutet, dass die Verwendung von Ersatzpaaren erforderlich ist, um Codepunkte außerhalb der mehrsprachigen Grundebene darzustellen. – rdb