2012-04-29 9 views
7

tengo un programa que imprima cadena UTF-8 en la consola:¿Cuál es la diferencia entre printf y std :: ostream debajo de la consola ventanas con UTF-8 salida

#include <stdio.h> 

int main() 
{ 
    printf("Мир Peace Ειρήνη\n"); 
    return 0; 
} 

puedo configurar la consola para utilizar Verdadero Tipo de letra (Lucida Console), definir códigos UTF-8 páginas (chcp 65001) compilar este programa con tanto MinGW GCC y Visual Studio 2010 que funciona perfectamente, veo: la salida:

Мир Peace Ειρήνη 

hago lo mismo utilizando std::cout

#include <iostream> 

int main() 
{ 
    std::cout << "Мир Peace Ειρήνη\n" ; 
    return 0; 
} 

Esto funciona perfectamente bien como el anterior usando MinGW GCC pero con Visual Studio 2010 obtengo cuadrados, más que eso los cuadrados (dos por cada letra no ASCII).

Si ejecuto el programa con la redirección test >test.txt obtengo la salida UTF-8 perfecta en el archivo.

Ambas pruebas realizadas en Windows 7.

Preguntas:

  1. ¿Cuál es la diferencia entre printf y std :: cout en el estudio de la biblioteca estándar visual en la manipulación del flujo de salida - con claridad uno de ellos funciona y el otro no?
  2. ¿Cómo se puede corregir esto?

respuesta real:

En resumen: que se atornillan - std::cout no funciona muy bien con MSVC + UTF-8 - o al menos requiere un enorme esfuerzo para hacer que se comporte razonablemente.

En largo: lea dos artículos a los que se hace referencia en la respuesta.

+0

No es seguro AFAIK para incrustar el Unicode directamente en su código fuente. Creo que la forma más segura es usar algún tipo de recurso o ingresar puntos de código Unicode con \ uy el u8 literal (C++ 11) –

+0

printf() que genera unicode y std :: cout también son asunto de [ Problemas Unicode en C++ pero no C] (http://stackoverflow.com/questions/21370710) – Salvador

Respuesta

1

usted tiene un número de suposiciones incorrectas, déjame corregir los primero:

  • Que las cosas parecen funcionar con g ++ no significa que g ++ funciona correctamente.

  • Visual Studio no es un compilador, es un IDE que admite muchos lenguajes y compiladores.

  • La conclusión de que la biblioteca estándar de Visual C++ debe corregirse es correcta, pero el razonamiento que lleva a esa conclusión es incorrecta. También se debe arreglar la biblioteca estándar de g ++. Por no mencionar el compilador g ++ en sí.

Ahora, Visual C++ tiene ANSI de Windows, la codificación especificada por la función GetACP API, como su juego de caracteres C++ ejecución indocumentado. Incluso si su código fuente es UTF-8 con BOM, las cadenas limitadas terminan traducidas a Windows ANSI. Si eso, en su computadora en el momento de la compilación, es una página de códigos que incluye todos los caracteres que no son ASCII, entonces OK, pero de lo contrario las cadenas estrechas se confunden.La descripción de los resultados de su prueba es por lo tanto seriamente incompleta sin mencionar la codificación del código fuente y cuál es su página de códigos ANSI de Windows.

Pero de todos modos, "Si ejecuto el programa con la redirección test >test.txt obtengo una salida UTF-8 perfecta en el archivo" indica que lo que enfrenta es un poco de ayuda de nivel C++ del tiempo de ejecución de Visual C++, donde puentea la salida de la secuencia y utiliza salida de consola directa para obtener los caracteres correctos que se muestran en la ventana de la consola.

Esta ayuda da como resultado la basura cuando sus suposiciones, como los literales de cadena estrecha con codificación ANSI de Windows, no se cumplen.

También significa que el efecto desaparece misteriosamente cuando se redirige la secuencia. La biblioteca de tiempo de ejecución luego detecta que la transmisión va a un archivo y desactiva la característica de salida de la consola directa. No está garantizado que obtenga los valores de bytes originales sin procesar, pero evidentemente lo hizo, lo cual fue mala suerte porque enmascaró el problema.

Por cierto, la página de códigos 65001 en la consola de Windows no se puede usar en la práctica. Muchos programas simplemente se cuelgan. Incluyendo, por ejemplo, more.


Una forma de obtener la salida correcta es usar el nivel API de Windows directamente, con salida de consola directa.

Obtener resultados correctos con las transmisiones en C++ es mucho más complicado.

Es tan complicado que no hay lugar para describirlo (¡correctamente!) Aquí, así que en su lugar tengo que referirme a mi serie de artículos de blog de 2 partes al respecto: part 1 y part 2.

+0

Tiene sentido. Pero, ¿cómo explica esto el problema del OP de que el programa genera _squares_? Esperaría la representación de la consola de los bytes UTF-8: para el ruso М (U + 0419) que sería \ xD0 \ x99, o ''╗' en mi máquina. –

+0

La cadena es UTF-8 (comprobada, realmente) Conozco todo el problema MSVC/UTF-8 (mierda). Sé manejarlo correctamente (de la fuente original UTF-8 sin BOM luego char * obtiene el UFF-8 correcto, por supuesto L "שלום" está en mal estado, pero esta es una historia diferente, puedo hacer lo mismo con los literales "\ xXY" , el resultado es el mismo: sobre las suposiciones, las suposiciones básicas son que 'std :: cout << str;' debe comportarse igual que 'puts (str)' Esta es la suposición y gcc hizo esto bien - al menos predecible. Ahora yo Entiendo claramente que 'std :: cout' usa alguna consola API que hace que el problema sea aún más grave (TBC ...) – Artyom

+2

porque no es algo realmente esperado. Finalmente encontré su artículo (parte 2), este http: // blogs.msdn.com/b/michkap/archive/2008/03/18/8306597.aspx El artículo de Kaplan y este informe de errores http://connect.microsoft.com/VisualStudio/feedback/details/431244/std-ostream-fails -to-write-utf-8-encoded-string-to-console. Finalmente, la única "solución" razonable es crear mi propio búfer de secuencia. T el suyo es otro ejemplo más del modelo Unicode de ventanas totalmente CRAPPY cuando la mitad de las aplicaciones no maneja bien Unicode. – Artyom

Cuestiones relacionadas