2012-04-04 14 views
5

Quando si usa printf per formattare una stringa di byte doppio in una stringa singolo byte:Perché i parametri Unicode del formato printf non vengono stampati?

printf("%ls\n", L"s:\\яшертыHello"); // %ls for a wide string (%s varies meaning depending on the project's unicode settings). 

Chiaramente, alcuni caratteri non possono essere rappresentati come caratteri ASCII, comportamento in modo a volte ho visto dove i caratteri a doppio byte diventare un '?' contrassegna il carattere. Ma questo sembra dipendere dai personaggi particolari. Per la printf sopra, l'output è:

s:\ 

Speravo che potrei ottenere qualcosa di simile:

s:\??????Hello 

Temo di aver perso l'esempio, ma credo che per una stringa quando ha incontrato caratteri unicode, sostituito il primo con un '?' e poi ha rinunciato al resto.

Quindi, la mia domanda è, cosa dovrebbe succedere quando si formatta una stringa larga in una stringa a singolo byte. Documentazione qui: http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx dice "I caratteri sono visualizzati fino al primo carattere null". Ma non lo vedo. È un bug in printf, o è il comportamento che sto vedendo documentato da qualche parte, se è così, dove.

Grazie per il vostro aiuto.

UPDATE

Grazie per le risposte da persone che danno a me alternative all'utilizzo printf. Cambierò in un'alternativa, ma sono davvero interessato alla curiosità perché la stampa non ha un comportamento documentato affidabile. Sembra quasi che se l'implementatore abbia fatto di tutto per farlo funzionare.

+2

Hai provato "% S" come identificatore di formato anziché "% ls"? –

+0

si. Credo che% S e% ls abbiano lo stesso significato se il tuo progetto non ha UNICODE definito. –

+1

Leggere le specifiche del formato (che sono d'accordo non sono chiare). S è per una stringa larga quando le impostazioni del progetto non hanno UNICODE definito, S è per una stringa a singolo byte quando si ha UNICODE definito. % ls è per una stringa ampia indipendentemente dal fatto che tu stia o meno per UNICODE o meno. % s varia anche il significato,% hs è sempre per stringhe a singolo byte. –

risposta

10

Mi aspetto che il tuo codice funzioni - e funziona qui su Linux - ma dipende dalle impostazioni internazionali. Ciò significa che devi impostare le impostazioni internazionali e che le tue impostazioni internazionali devono supportare il set di caratteri utilizzato. Ecco il mio programma di test:

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

int main() 
{ 
    int c; 
    char* l = setlocale(LC_ALL, ""); 
    if (l == NULL) { 
     printf("Locale not set\n"); 
    } else { 
     printf("Locale set to %s\n", l); 
    } 
    printf("%ls\n", L"s:\\яшертыHello"); 
    return 0; 
} 

e qui è una traccia di esecuzione:

$ env LC_ALL=en_US.utf8 ./a.out 
Locale set to en_US.utf8 
s:\яшертыHello 

Se si dice che il locale non è impostato o è impostato su "C", è normale che si non ottenere il risultato che ti aspetti

Modifica: vedere le risposte a this question per l'equivalente di en_US.utf8 per Windows.

+0

Hmm. Questa risposta sembra nel giusto tipo di area. Mi chiedo come hai impostato il tuo locale su utf8 però ... quando ci provo, setlocale fallisce. I documenti qui: http://msdn.microsoft.com/en-us/library/x99tb11d.aspx (se cerchi utf-8) dice che fallirà se proverai utf-8. Forse non funziona nell'implementazione di Microsoft. –

+0

@ScottLangham, i nomi delle impostazioni internazionali non sono standardizzati e non so cosa sia supportato in Windows, ma sarei sorpreso se non hanno alcun Unicode - non necessariamente UTF8 - locale. – AProgrammer

+1

Windows non supporta le impostazioni locali "Unicode". Su tutte le implementazioni la codifica di wchar_t è indipendente dalle impostazioni locali, quindi la codifica di una locale si riferisce solo alla codifica dei caratteri stretti. Quindi un locale "Unicode" richiede essenzialmente UTF-8 e Windows non fornisce alcuna localizzazione usando UTF-8. Windows supporta Unicode utilizzando UTF-16 come codifica wchar_t. – bames53

5

In C++ di solito uso std::stringstream per creare testo formattato. Ho anche implementato una propria all'operatore di utilizzare la funzione di Windows per rendere la codifica:

ostream & operator << (ostream &os, const wchar_t * str) 
{ 
    if ((str == 0) || (str[0] == L'\0')) 
    return os; 
    int new_size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, NULL, NULL, NULL); 
    if (new_size <= 0) 
    return os; 
    std::vector<char> buffer(new_size); 
    if (WideCharToMultiByte(CP_UTF8, 0, str, -1, &buffer[0], new_size, NULL, NULL) > 0) 
    os << &buffer[0]; 
    return os; 
} 

Questo codice convertire in UTF-8. Per altre possibilità controllare: WideCharToMultiByte.

+0

Bel esempio di come farlo :) – jcoder

+0

@JohnB: grazie! :) – Naszta

Problemi correlati