2013-03-20 15 views
18

In Anweisungen wie diesen, wo beide in den Quellcode mit der gleichen Codierung (UTF-8) eingegeben werden und das Gebietsschema richtig eingerichtet ist, gibt es keine praktischer Unterschied zwischen ihnen?Drucken von UTF-8-Zeichenfolgen mit printf - Wide oder Multibyte-Zeichenfolgenliteralen

printf("ο Δικαιοπολις εν αγρω εστιν\n"); 
printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν\n"); 

Und folglich gibt es irgendeinen Grund, einen vor dem anderen zu bevorzugen, wenn man Ausgabe macht? Ich stelle mir vor, dass die zweite etwas schlechter abschneidet, aber hat sie einen Vorteil (oder Nachteil) gegenüber einem Multibyte-Literal?

EDIT: Es gibt keine Probleme mit diesen Strings Drucken. Aber ich benutze die Wide-String-Funktionen nicht, weil ich auch printf usw. verwenden möchte. Die Frage ist also, ob diese Art des Druckens anders ist (angesichts der oben beschriebenen Situation), und wenn ja, hat die zweite einen Vorteil?

EDIT2: die Kommentare unten Nach, ich weiß jetzt, dass dieses Programm funktioniert - das fand ich doch nicht möglich war:

int main() 
{ 
    setlocale(LC_ALL, ""); 
    wprintf(L"ο Δικαιοπολις εν αγρω εστιν\n"); // wide output 
    freopen(NULL, "w", stdout);     // lets me switch 
    printf("ο Δικαιοπολις εν αγρω εστιν\n"); // byte output 
} 

EDIT3: ich einige weitere Forschung getan haben durch schauen, was mit den beiden Typen los ist. Nehmen Sie eine einfachere Zeichenfolge:

wchar_t *wides = L"£100 π"; 
char *mbs = "£100 π"; 

Der Compiler generiert anderen Code. Die breite Zeichenfolge ist:

.string "\243" 
.string "" 
.string "" 
.string "1" 
.string "" 
.string "" 
.string "0" 
.string "" 
.string "" 
.string "0" 
.string "" 
.string "" 
.string " " 
.string "" 
.string "" 
.string "\300\003" 
.string "" 
.string "" 
.string "" 
.string "" 
.string "" 

Während der zweite ist:

.string "\302\243100 \317\200" 

Und bei den Unicode-Codierungen suchen, die zweite Ebene UTF-8. Die breite Zeichendarstellung ist UTF-32. Ich weiß, dass dies von der Implementierung abhängig sein wird.

Also ist vielleicht die breite Zeichendarstellung von Literalen tragbarer? Mein System druckt UTF-16/UTF-32-Kodierungen nicht direkt, sondern wird zur Ausgabe automatisch in UTF-8 konvertiert.

+0

Sie sagten beide Beispiele mit UTF-8 eingegeben werden. Wenn der Text in der zweiten Beispielzeile eher UTF-8 als eine breite Kodierung ist, dann sollten Sie wahrscheinlich nicht das L-Präfix haben, und deshalb würden Sie nur '% s' statt '% ls' verwenden. Oder ich verstehe die Frage immer noch falsch. –

+0

@AdrianMcCarthy - beide Zeichenfolgen im Quellcode sind UTF-8, ja. Aber ein String-Literal ist immer Multibyte - "Ein Zeichenketten-Literal ist eine Folge von null oder mehr Multibyte-Zeichen in Anführungszeichen, wie in" xyz ". Ein breites String-Literal ist das gleiche, außer durch den Buchstaben L vorfixiert. " vom Standard. – teppic

+0

AFAIR, alle Zeichen, die nicht im Basic Source Character Set sind (was eine * Teilmenge * von US-ASCII-7 ist), rufen implementationsdefiniertes Verhalten auf, d.h. alles, was hier diskutiert wird, hängt effektiv vom verwendeten Compiler ab. Wenn Sie wirklich auf Nummer sicher gehen wollen (und portabel), müssten Sie auf \ u ... und \ U ... zurückgreifen. – DevSolar

Antwort

20
printf("ο Δικαιοπολις εν αγρω εστιν\n"); 

druckt den Stringliteral (const char*, Sonderzeichen werden als multibyte Zeichen dargestellt). Obwohl Sie möglicherweise die richtige Ausgabe sehen, gibt es andere Probleme, mit denen Sie möglicherweise beim Arbeiten mit Nicht-ASCII-Zeichen wie diesen zu tun haben. Zum Beispiel:

char str[] = "αγρω"; 
printf("%d %d\n", sizeof(str), strlen(str)); 

9 8 Ausgänge, wobei jeder dieser Sonderzeichen, da durch 2 char s dargestellt wird.

Während des L Präfix haben Sie die wörtliche aus breiten Zeichen (const wchar_t*) und %ls Formatspezifizierer führt diese breiten Zeichen Mehrbytezeichen umgewandelt werden (UTF-8). Beachten Sie, dass in diesem Fall locale sollte diese Umsetzung könnte in geeigneter Weise auf andere Weise eingestellt wird, führen zu dem Ausgang ungültig sein:

#include <stdio.h> 
#include <wchar.h> 
#include <locale.h> 

int main(void) 
{ 
    setlocale(LC_ALL, ""); 
    printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν"); 
    return 0; 
} 

aber während einige Dinge vielleicht komplizierter, wenn sie mit breiten Zeichen arbeiten, andere Dinge könnten viel einfacher bekommen und direkter.Zum Beispiel:

wchar_t str[] = L"αγρω"; 
printf("%d %d", sizeof(str)/sizeof(wchar_t), wcslen(str)); 

ausgeben wird 5 4 als würde man natürlich erwarten.

Sobald Sie sich entscheiden, mit breiten Strings zu arbeiten, kann wprintf verwendet werden, breite Zeichen direkt zu drucken. Es lohnt sich auch hier zu beachten, dass die Übersetzungsmodus des stdout bei Windows-Konsole, sollte ausdrücklich von _setmode Aufruf zu einer der Unicode-Modi eingestellt werden:

#include <stdio.h> 
#include <wchar.h> 

#include <io.h> 
#include <fcntl.h> 
#ifndef _O_U16TEXT 
    #define _O_U16TEXT 0x20000 
#endif 

int main() 
{ 
    _setmode(_fileno(stdout), _O_U16TEXT); 
    wprintf(L"%s\n", L"ο Δικαιοπολις εν αγρω εστιν"); 
    return 0; 
} 
+0

Das bin ich :) 'wprintf' konvertiert auch zu Multibyte, aber ich bin an den Standardfunktionen interessiert. – teppic

+0

@steppic: Siehe meine Antwort jetzt. Es sollte endlich befriedigender sein, denke ich :) – LihO

+5

UTF-16 ist ** nicht ** "breit", und es ist wirklich eine Schande, dass dieses bisschen Mythos immer noch da ist. Es gibt mehr als 2^16 Unicode-Zeichen, und UTF-16 codiert sie mit einer ** variablen ** Breite von entweder einer oder zwei 16-Bit-Code-Einheiten. Wenn Sie "weit" möchten, müssen Sie auf UTF-32 zurückgreifen. Gehen wir nicht in die Falle, zu denken, dass 'n' Bit für alle * wieder * genug sein sollte. – DevSolar