Stampa di stringhe UTF-8 con valori letterali stringa printf – wide vs. multibyte

In affermazioni come queste, dove entrambi sono inseriti nel codice sorgente con la stessa codifica (UTF-8) e le impostazioni internazionali sono configurate correttamente, c’è qualche differenza pratica tra loro?

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

E di conseguenza c’è qualche motivo per preferire uno rispetto all’altro quando si fa l’output? Immagino che il secondo si comporti un po ‘peggio, ma ha qualche vantaggio (o svantaggio) su un letterale multibyte?

EDIT: non ci sono problemi con queste stringhe di stampa. Ma non sto usando le ampie funzioni di stringa, perché voglio essere in grado di usare anche printf ecc. Quindi la domanda è: questi modi di stampare sono diversi (data la situazione descritta sopra), e in caso affermativo, il secondo ha qualche vantaggio?

EDIT2: Seguendo i commenti qui sotto, ora so che questo programma funziona – cosa che pensavo non fosse ansible:

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

EDIT3 : Ho fatto qualche ulteriore ricerca guardando a cosa sta succedendo con i due tipi. Prendi una stringa più semplice:

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

Il compilatore sta generando un codice diverso. La stringa ampia è:

 .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 "" 

Mentre il secondo è:

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

E guardando le codifiche Unicode, il secondo è semplice UTF-8. L’ampia rappresentazione dei caratteri è UTF-32. Mi rendo conto che questo dipenderà dall’implementazione.

Quindi forse la rappresentazione a caratteri ampi dei letterali è più portabile? Il mio sistema non stampa direttamente le codifiche UTF-16 / UTF-32, quindi viene convertito automaticamente in UTF-8 per l’output.

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

stampa la stringa letterale ( const char* , i caratteri speciali sono rappresentati come caratteri multibyte ). Sebbene tu possa vedere l’output corretto, ci sono altri problemi che potresti avere mentre lavori con caratteri non ASCII come questi. Per esempio:

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

uscite 9 8 , poiché ognuno di questi caratteri speciali è rappresentato da 2 char .

Mentre si usa il prefisso L si ha il letterale costituito da caratteri ampi ( const wchar_t* ) e l’ %ls formato %ls fa sì che questi caratteri ampi vengano convertiti in caratteri multibyte (UTF-8). Nota che in questo caso, le impostazioni internazionali dovrebbero essere impostate in modo appropriato altrimenti questa conversione potrebbe rendere l’output non valido:

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

ma mentre alcune cose potrebbero diventare più complicate quando si lavora con caratteri ampi, altre cose potrebbero diventare molto più semplici e più semplici. Per esempio:

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

emetterà 5 4 come ci si aspetterebbe naturalmente.

Una volta deciso di lavorare con stringhe larghe, wprintf può essere utilizzato per stampare direttamente caratteri ampi . Vale anche la pena notare che in caso di console Windows, la modalità di traduzione dello stdout deve essere impostata esplicitamente su una delle modalità Unicode chiamando _setmode :

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