2009-12-07 12 views
13

Non essendo in grado di avvolgere la mia testa intorno a questo è una vera e propria fonte di vergogna ...C++ emette

sto lavorando con una versione francese di Visual Studio (2008), in un francese Windows XP). Gli accenti francesi messi nelle stringhe inviate alla finestra di output vengono corrotti. Idem inserendo da la finestra di output. Tipico problema di codifica dei caratteri, inserisco ANSI, ottengo UTF-8 in cambio, o qualcosa del genere. Quale impostazione può garantire che i caratteri rimangano in ANSI quando si mostra una stringa "hardcoded" alla finestra di output?

EDIT:

Esempio:

#include <iostream> 

int main() 
{ 
std:: cout << "àéêù" << std:: endl; 

return 0; 
} 

mostrerà in uscita:

óúÛ¨

(qui codificato in formato HTML per il vostro piacere di osservazione)

Mi piacerebbe davvero per mostrare:

àéêù

+0

Potete darci un po 'più di input. Sta succedendo per l'output di build, tutto l'output o qualcos'altro? Puoi darci una specifica operazione per la quale ciò accade (compilazione, debugging, ecc ...) – JaredPar

+0

Sì, per favore mostra un esempio di ciò che pensi dovrebbe apparire e ciò che effettivamente appare. – wallyk

+1

Cosa succede se usi wcout? – Naveen

risposta

13

Prima di andare oltre, dovrei ricordare che ciò che state facendo non è conforme a c/C++. Lo specification afferma in 2.2 quali set di caratteri sono validi nel codice sorgente. Non è molto in là, e tutti i personaggi usati sono in ascii. Quindi ... Tutto quanto segue riguarda un'implementazione specifica (come succede, VC2008 su un computer locale statunitense).

Per iniziare, hai 4 caratteri sulla riga cout e 4 glifi sull'output. Quindi il problema non è quello della codifica UTF8, poiché combinerebbe più caratteri di origine con meno glifi.

Da te stringa di origine per la visualizzazione sulla console, tutte quelle cose giocano una parte:

  1. Qual codifica il file sorgente è in (vale a dire come il file C++ sarà visto dal compilatore)
  2. che il compilatore fa con una stringa letterale, e quale fonte codifica capisce
  3. come il vostro << interpreta la stringa codificata che stai passando
  4. quello che codifica per la consolle si aspetta
  5. come la console traduce quell'output in un glifo font.

Ora ...

1 e 2 sono abbastanza facili. Sembra che il compilatore indovini in che formato si trova il file sorgente e lo decodifica nella sua rappresentazione interna. Genera il segmento di dati corrispondente letterale della stringa nella codepage corrente indipendentemente dalla codifica sorgente. Non sono riuscito a trovare dettagli/controlli espliciti su questo.

3 è ancora più semplice. Ad eccezione dei codici di controllo, << passa semplicemente i dati in basso per char *.

4 è controllato da SetConsoleOutputCP. Dovrebbe essere l'impostazione predefinita per la codepage predefinita del sistema. Puoi anche scoprire quale hai con GetConsoleOutputCP (l'input è controllato in modo diverso, tramite SetConsoleCP)

5 è divertente. Ho sbattuto la testa per capire perché non riuscivo a far apparire correttamente l'é, usando CP1252 (Europa occidentale, finestre). Si scopre che il mio font di sistema non ha il glifo per quel personaggio, e usa utilmente il glifo della mia codepage standard (capitale Theta, lo stesso che otterrei se non chiamassi SetConsoleOutputCP). Per risolverlo, ho dovuto cambiare il font che uso sulle console in Lucida Console (un font di tipo true).

Alcune cose interessanti che ho imparato a guardare questo:

  • la codifica della fonte non importa, fintanto che il compilatore può capirlo (in particolare, cambiandolo in UTF8 non modificare il codice generato La mia stringa "é" era ancora codificata con CP1252 come 233 0)
  • VC sta selezionando una codepage per i letterali stringa che non sembra controllare.
  • controllano ciò che gli spettacoli console è più doloroso di quello che mi aspettavo

Quindi ... che cosa significa questo per voi? Ecco alcuni consigli:

  • non utilizzare non-ascii in stringhe letterali. Utilizzare le risorse, dove è controllare la codifica.
  • assicurati di sapere quale codifica è prevista dalla tua console e che il tuo font ha i glifi per rappresentare i caratteri che invii.
  • se si desidera capire quale codifica viene utilizzata nel proprio caso, si consiglia di stampare il valore effettivo del carattere come numero intero. char * a = "é"; std::cout << (unsigned int) (unsigned char) a[0] mostra per me 233, che risulta essere la codifica in CP1252.

A proposito, se quel che abbiamo ottenuto è stato "Ouu" piuttosto che ciò che è stato incollato, allora sembra che il tuo 4 byte sono interpretati da qualche parte come CP850.

+0

Utilizzo delle risorse .. Sicuramente dobbiamo dare un'occhiata a questo. Qui è dove diventa più difficile: la console funge da filtro di sorta, perché se io "cin >>" alcune lettere accentate, ecco, personaggi divertenti si ottengono dall'altra parte! Al momento non sono in quella macchina, ma proverò a reoutput quello che ottengo da cin e vedere se diventa ulteriormente confonduto o torna indietro. – MPelletier

+0

Ottima risposta. Certamente ne prenderò nota. –

+0

Questa risposta è molto utile per capire cosa succede ai byte grezzi del file del codice sorgente per una stringa letterale attraverso il processo di compilazione e attraverso il sistema di runtime. Forse potresti dare un'occhiata a http://stackoverflow.com/questions/27871124/does-the-multibyte-to-wide-string-conversion-function-mbstowcs-when-passed-a? –

2

Ho provato questo codice:

#include <iostream> 
#include <fstream> 
#include <sstream> 

int main() 
{ 
    std::wstringstream wss; 
    wss << L"àéêù"; 
    std::wstring s = wss.str(); 
    const wchar_t* p = s.c_str(); 
    std::wcout << ws.str() << std::endl; 

    std::wofstream file("C:\\a.txt"); 
    file << p << endl; 

    return 0; 
} 

Il debugger mostrato che wss, s p e avevano tutti i valori attesi (cioè "àéêù"), così come il file di output. Tuttavia, ciò che è apparso nella console è stato óúÛ¨.

Il problema è quindi nella console di Visual Studio, non nel C++. Utilizzando risposta eccellente del Bahbar, ho aggiunto:

SetConsoleOutputCP(1252); 

come la prima linea, e l'uscita della console, allora è apparso come dovrebbe.

4

Prova questo:

#include <iostream> 
#include <locale> 

int main() 
{ 
std::locale::global(std::locale("")); 
std::cout << "àéêù" << std::endl; 

return 0; 
} 
+0

Bello, ma questo sembra funzionare solo per l'output, l'input ricevuto dalla console è ancora casuale senza senso. –

0
//Save As Windows 1252 
#include<iostream> 
#include<windows.h> 

int main() 
{ 
    SetConsoleOutputCP(1252); 
    std:: cout << "àéêù" << std:: endl; 
} 

Visual Studio non supporta UTF 8 per C++, ma in parte supporti per C:

//Save As UTF8 without signature 
#include<stdio.h> 
#include<windows.h> 

int main() 
{ 
    SetConsoleOutputCP(65001); 
    printf("àéêù\n"); 
} 
0

Assicurarsi di non dimenticare di cambiamento della il font della console per Lucida Consolas come menzionato da Bahbar: è stato cruciale nel mio caso (vittoria francese 7 64 bit con VC 2012).

Quindi come menzionato da altri utilizzi SetConsoleOutputCP (1252) per C++ ma potrebbe non riuscire a seconda delle pagine disponibili quindi potresti voler utilizzare GetConsoleOutputCP() per verificare che funzioni o almeno per controllare che SetConsoleOutputCP (1252) restituisca zero. Cambiare il locale globale funziona anche (per qualche motivo non c'è bisogno di fare cout.imbue (locale());! Ma può rompere alcune Librairies

In C, SetConsoleOutputCP (65001), oppure il locale- approccio ha funzionato per me una volta che avessi salvato il codice sorgente come UTF8 senza la firma (scorrere verso il basso, la scelta sans-firma è ben al di sotto nella lista delle pagine)

ingresso utilizzando SetConsoleCP (65001).; fallito per me apparentemente a causa di una cattiva implementazione della pagina 65001 in Windows. L'approccio locale è fallito sia in C che in C++. Una soluzione più coinvolta, non basata su caratteri nativi ma su wchar_t sembra obbligatorio

1

L'utilizzo di _setmode() funziona con (source) ed è probabilmente meglio che modificare la codepage o impostare una locale, poiché in realtà farà in modo che il programma usi Unicode. Esempio:

#include <iostream> 
#include <io.h> 
#include <fcntl.h> 

int wmain() 
{ 
    _setmode(_fileno(stdout), _O_U16TEXT); 

    std::wcout << L"àéêù" << std::endl; 

    return 0; 
} 


all'interno di Visual Studio, assicuratevi di impostare il vostro progetto per Unicode (tasto destro del mouse Progetto -> Clicca Generale ->Character Set = Usa Unicode set di caratteri).

utenti

MinGW:

  1. definire sia UNICODE e _UNICODE
  2. Aggiungi -finput-charset=iso-8859-1 alle opzioni compilatore Per ovviare a questo errore: "conversione al set di caratteri esecuzione: Invalid argument"
  3. Aggiungi -municode alle opzioni di collegamento per spostarsi "non definito riferimento a `WinMain @ 16" (read more).