2009-12-07 19 views
13

No ser capaz de envolver mi cabeza alrededor de éste es una verdadera fuente de vergüenza ...C++ Visual Studio carácter codificación emite

Estoy trabajando con una versión francesa de Visual Studio (2008), en un francés Windows XP). Los acentos franceses colocados en cadenas enviadas a la ventana de salida se corrompen. Ídem entrada desde la ventana de salida. Problema típico de codificación de caracteres, ingreso a ANSI, obtengo UTF-8 a cambio, o algo por el estilo. ¿Qué configuración puede garantizar que los caracteres permanezcan en ANSI cuando se muestra una cadena "codificada" en la ventana de salida?

EDIT:

Ejemplo:

#include <iostream> 

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

return 0; 
} 

se mostrará en la salida:

óúÛ¨

(aquí codificado como HTML para su placer visual)

Realmente me gustaría para mostrar:

àéêù

+0

¿Nos puede dar un poco más de entrada. ¿Esto está sucediendo para la producción de compilación, todos los resultados o algo más? ¿Puede darnos una operación específica para la que esto sucede (creación, depuración, etc.) – JaredPar

+0

Sí, muestre un ejemplo de lo que cree que debería aparecer y lo que realmente aparece. – wallyk

+1

¿Qué sucede si usa wcout? – Naveen

Respuesta

13

Antes de continuar, debo mencionar que lo que está haciendo no es compatible con C/C++. El specification indica en 2.2 qué conjuntos de caracteres son válidos en el código fuente. No hay mucho allí, y todos los personajes utilizados están en ascii. Entonces ... Todo a continuación es sobre una implementación específica (como ocurre, VC2008 en una máquina local de EE. UU.).

Para empezar, tiene 4 caracteres en su línea cout, y 4 glifos en la salida. Por lo tanto, el problema no es la codificación UTF8, ya que combinaría varios caracteres fuente en menos glifos.

De ti cadena de origen a la pantalla de la consola, todas esas cosas juegan un papel importante:

  1. Lo que codifica el archivo de origen está en (es decir, cómo el archivo de C++ será visto por el compilador)
  2. lo que su compilador hace con una cadena literal, y qué fuente que lo codifica entiende
  3. cómo su << interpreta la cadena codificada que está pasando en
  4. lo codifica la consola de espera
  5. cómo la consola traduce esa salida a un glifo de fuente.

Ahora ...

1 y 2 son bastante fáciles. Parece que el compilador adivina en qué formato se encuentra el archivo fuente y lo decodifica en su representación interna. Genera el literal de cadena correspondiente a la porción de datos en la página de códigos actual independientemente de la codificación de origen. No he podido encontrar detalles/control explícitos sobre esto.

3 es aún más fácil. A excepción de los códigos de control, << simplemente pasa los datos por char *.

4 es controlado por SetConsoleOutputCP. Debería establecerse de forma predeterminada en la página de códigos predeterminada del sistema. También puede averiguar cuál tiene con GetConsoleOutputCP (la entrada se controla de manera diferente, a través de SetConsoleCP)

5 es divertido. Me golpeé la cabeza para descubrir por qué no podía hacer que el é se mostrara correctamente, usando CP1252 (europeo occidental, Windows). Resulta que la fuente de mi sistema no tiene el glifo para ese personaje, y usa útilmente el glifo de mi página de códigos estándar (mayúscula Theta, lo mismo que obtendría si no llamara a SetConsoleOutputCP). Para solucionarlo, tuve que cambiar la fuente que uso en las consolas a Lucida Console (una verdadera tipografía).

Algunas cosas interesantes que aprendí mirando esto:

  • la codificación de la fuente no importa, siempre y cuando el compilador puede averiguarlo (en particular, cambiándolo a UTF8 no cambió el código generado . Mi cadena "é" aún estaba codificada con CP1252 como 233 0)
  • VC está seleccionando una página de códigos para los literales de cadenas que no parecen controlar.
  • controlando lo que muestra la consola es más doloroso que lo que estaba esperando

Así que ... ¿qué significa esto para usted? Estos son algunos consejos:

  • no utilice non-ascii en cadenas literales. Use los recursos, donde usted controla la codificación.
  • asegúrate de saber qué codificación espera la consola y que tu fuente tenga los glifos para representar los caracteres que envíes.
  • si desea saber qué codificación se está utilizando en su caso, le aconsejo que imprima el valor real del carácter como un número entero. char * a = "é"; std::cout << (unsigned int) (unsigned char) a[0] muestra 233 para mí, que es la codificación en CP1252.

Por cierto, si lo que se obtuvo fue "Ouu" en lugar de lo que ha pegado, entonces parece que los 4 bytes se interpretan como un lugar CP850.

+0

Usando recursos ... Definitivamente tengo que investigar eso. Sin embargo, aquí es donde se hace más difícil: la consola actúa como un filtro de tipo, porque si "cin >>" algunas letras acentuadas, he aquí, ¡personajes divertidos se ponen del otro lado! No estoy en esa máquina en este momento, pero intentaré informar lo que recibo de cin y ver si se confunde más o si vuelve a aparecer. – MPelletier

+0

Excelente respuesta. Definitivamente voy a tomar nota de esto. –

+0

Esta respuesta es bastante útil para comprender qué sucede con los bytes sin formato del archivo de código fuente para un literal de cadena a través del proceso de compilación y hasta el sistema de tiempo de ejecución. Tal vez podría echarle un vistazo a http://stackoverflow.com/questions/27871124/does-the-multibyte-to-wide-string-conversion-function-mbstowcs-when-passed-a? –

2

yo probamos este código:

#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; 
} 

El depurador mostró que WSS, s yp todos tenían los valores esperados (es decir, "àéêù"), al igual que el archivo de salida. Sin embargo, lo que apareció en la consola fue óúÛ¨.

El problema está, por lo tanto, en la consola de Visual Studio, no en C++. Usando una excelente respuesta de Bahbar, añadí:

SetConsoleOutputCP(1252); 

como la primera línea, y la salida de la consola entonces apareció como debería.

4

Prueba esto:

#include <iostream> 
#include <locale> 

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

return 0; 
} 
+0

Bueno, pero parece que solo funciona para la salida, la entrada recibida de la consola sigue siendo un galimatías aleatorio. –

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

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

Visual Studio no es compatible con UTF-8 para C++, pero parcialmente apoya para C:

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

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

Asegúrese de que no se olvide a cambio de la fuente de la consola a Lucida Consolas mencionada por Bahbar: fue crucial en mi caso (victoria francesa 7 64 bit con VC 2012).

Entonces, como lo mencionan en otros utilizan SetConsoleOutputCP (1252) para C++, pero puede fallar dependiendo de las páginas disponibles así que es posible que desee utilizar GetConsoleOutputCP() para comprobar que funcionaba o al menos para comprobar que SetConsoleOutputCP (1252) vuelve cero. Cambiar la configuración regional global también funciona (por alguna razón no hay necesidad de hacer cout.imbue (locale());! Pero puede romper algunos Librairies

En C, SetConsoleOutputCP (65001), o la locale- enfoque basado trabajó para mí una vez que había guardado el código fuente como UTF8 sin la firma (desplazarse hacia abajo, la elección sans-firma está muy por debajo de la lista de páginas)

entrada usando SetConsoleCP (65001).; falló para mí aparentemente debido a una mala implementación de la página 65001 en Windows. El enfoque de configuración regional también falló en C y C++. Una solución más complicada, sin depender de los caracteres nativos sino de wchar_t parece requerido.

1

El uso de _setmode() funciona (source) y es posiblemente mejor que cambiar la página de códigos o establecer una configuración regional, ya que de hecho hará que su programa utilice Unicode. Ejemplo:

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

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

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

    return 0; 
} 


dentro de Visual Studio, asegúrese de configurar el proyecto para Unicode (Haga clic derecho Proyecto -> Haga clic general ->juego de caracteres = Uso de caracteres Unicode Conjunto)

usuarios

MinGW:

  1. definir tanto UNICODE y _UNICODE
  2. Añadir -finput-charset=iso-8859-1 a los opciones del compilador Para solucionar este error: "convirtiendo al conjunto de caracteres de ejecución: Argumento no válido"
  3. Agregue -municode a las opciones del vinculador para obtener "undefined referencia a `WinMain @ 16" (read more).
Cuestiones relacionadas