Impresión de cadenas UTF-8 con literales de cadena de printf-wide vs. multibyte
unicode c++ (1)
printf("ο Δικαιοπολις εν αγρω εστιν/n");
imprime la cadena literal ( const char*
, los caracteres especiales se representan como caracteres multibyte ). Aunque es posible que vea la salida correcta, hay otros problemas con los que podría estar tratando mientras trabaja con caracteres que no son ASCII como estos. Por ejemplo:
char str[] = "αγρω";
printf("%d %d/n", sizeof(str), strlen(str));
Salidas 9 8
, ya que cada uno de estos caracteres especiales está representado por 2 caracteres s.
Mientras usa el prefijo L
, tiene el literal que consta de caracteres anchos ( const wchar_t*
) y el especificador de formato %ls
hace que estos caracteres anchos se conviertan en caracteres multibyte (UTF-8). Tenga en cuenta que, en este caso, la configuración regional se debe establecer de forma adecuada, de lo contrario, esta conversión podría hacer que la salida no sea válida:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main(void)
{
setlocale(LC_ALL, "");
printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν");
return 0;
}
pero mientras algunas cosas pueden complicarse más cuando se trabaja con caracteres anchos, otras pueden ser mucho más simples y directas. Por ejemplo:
wchar_t str[] = L"αγρω";
printf("%d %d", sizeof(str) / sizeof(wchar_t), wcslen(str));
producirá 5 4
como uno esperaría naturalmente.
Una vez que decida trabajar con cadenas anchas, wprintf
puede usarse para imprimir caracteres anchos directamente. También vale la pena tener en cuenta que en el caso de la consola de Windows, el modo de traducción de la _setmode
debe establecer explícitamente en uno de los modos Unicode llamando a _setmode
:
#include <stdio.h>
#include <wchar.h>
#include <io.h>
#include <fcntl.h>
#ifndef _O_U16TEXT
#define _O_U16TEXT 0x20000
#endif
int main()
{
_setmode(_fileno(stdout), _O_U16TEXT);
wprintf(L"%s/n", L"ο Δικαιοπολις εν αγρω εστιν");
return 0;
}
En declaraciones como estas, donde ambas se ingresan en el código fuente con la misma codificación (UTF-8) y la configuración regional está configurada correctamente, ¿hay alguna diferencia práctica entre ellas?
printf("ο Δικαιοπολις εν αγρω εστιν/n");
printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν/n");
Y, en consecuencia, ¿hay alguna razón para preferir una sobre la otra cuando se hace una salida? Me imagino que el segundo se desempeña un poco peor, pero ¿tiene alguna ventaja (o desventaja) sobre un literal de varios bytes?
EDIT: No hay problemas con la impresión de estas cadenas. Pero no estoy usando las funciones de cadena ancha, porque también quiero poder usar printf
etc. Entonces, la pregunta es si estas formas de imprimir son diferentes (dada la situación descrita anteriormente), y si es así, ¿la segunda tiene alguna ventaja?
EDIT2: Siguiendo los comentarios a continuación, ahora sé que este programa funciona, lo que pensé que no era posible:
int main()
{
setlocale(LC_ALL, "");
wprintf(L"ο Δικαιοπολις εν αγρω εστιν/n"); // wide output
freopen(NULL, "w", stdout); // lets me switch
printf("ο Δικαιοπολις εν αγρω εστιν/n"); // byte output
}
EDIT3 : He investigado un poco más lo que está pasando con los dos tipos. Toma una cadena más simple:
wchar_t *wides = L"£100 π";
char *mbs = "£100 π";
El compilador está generando un código diferente. La cadena ancha es:
.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 ""
Mientras que el segundo es:
.string "/302/243100 /317/200"
Y en cuanto a las codificaciones de Unicode, la segunda es UTF-8 simple. La representación de caracteres anchos es UTF-32. Me doy cuenta de que esto dependerá de la implementación.
Entonces, ¿tal vez la representación de caracteres literales es más portátil? Mi sistema no imprimirá las codificaciones UTF-16 / UTF-32 directamente, por lo que se convertirá automáticamente a UTF-8 para la salida.