Aquí hay algunas respuestas muy buenas, pero creo que hay un par de cosas que puedo agregar con respecto a Windows / Visual Studio. Esto se basa en mi experiencia con VS2015. En Linux, básicamente la respuesta es usar UTF-8 codificado en std::string
todas partes. En Windows / VS se vuelve más complejo. Aquí es por qué. Windows espera que las cadenas almacenadas con char
s se codifiquen con la página de códigos de configuración regional. Este es casi siempre el conjunto de caracteres ASCII seguido de otros 128 caracteres especiales dependiendo de su ubicación. Permítanme decir que esto no solo cuando se usa la API de Windows, hay otros tres lugares importantes donde estas cadenas interactúan con C ++ estándar. Estos son literales de cadena, enviados a std::cout
usar <<
y pasando un nombre de archivo a std::fstream
.
Aquí voy a decir que soy programador, no especialista en idiomas. Aprecio que USC2 y UTF-16 no sean lo mismo, pero para mis propósitos están lo suficientemente cerca como para ser intercambiables y los uso como tales aquí. En realidad, no estoy seguro de qué Windows usa, pero generalmente tampoco necesito saberlo. He dicho UCS2 en esta respuesta, lo siento de antemano si molesto a alguien con mi ignorancia de este asunto y estoy feliz de cambiarlo si tengo algo mal.
Literales de cadena
Si ingresa literales de cadena que contienen solo caracteres que pueden ser representados por su página de códigos, entonces VS los almacena en su archivo con 1 byte por codificación de caracteres basado en su página de códigos. Tenga en cuenta que si cambia su página de códigos o le da su fuente a otro desarrollador usando una página de códigos diferente, entonces creo (pero no lo he probado) que el personaje terminará siendo diferente. Si ejecuta su código en una computadora usando una página de códigos diferente, entonces no estoy seguro de si el carácter también cambiará.
Si ingresa algún literal de cadena que no pueda ser representado por su página de códigos, VS le pedirá que guarde el archivo como Unicode. El archivo se codificará como UTF-8. Esto significa que todos los caracteres no ASCII (incluidos los que están en su página de códigos) estarán representados por 2 o más bytes. Esto significa que si le das tu fuente a otra persona, la fuente se verá igual. Sin embargo, antes de pasar la fuente al compilador, VS convierte el texto codificado UTF-8 en texto codificado en la página de códigos y los caracteres que faltan en la página de códigos se reemplazan con?
.
La única forma de garantizar la representación correcta de un literal de cadena Unicode en VS es preceder al literal de cadena con un L
literal de cadena ancha. En este caso, VS convertirá el texto codificado UTF-8 del archivo a UCS2. Luego debe pasar este literal de cadena a un std::wstring
constructor o debe convertirlo a utf-8 y ponerlo en a std::string
. O si lo desea, puede usar las funciones de la API de Windows para codificarlo usando su página de códigos para ponerlo en un std::string
, pero es posible que tampoco haya usado un literal de cadena ancha.
std :: cout
Cuando salga a la consola usando <<
solo puede usar std::string
, no, std::wstring
y el texto debe codificarse usando su página de códigos de configuración regional. Si tiene un std::wstring
archivo, debe convertirlo usando una de las funciones de la API de Windows y los caracteres que no estén en su página de códigos serán reemplazados por ?
(tal vez pueda cambiar el carácter, no recuerdo).
std :: nombres de archivos fstream
El sistema operativo Windows usa UCS2 / UTF-16 para sus nombres de archivo, por lo que sea cual sea su página de códigos, puede tener archivos con cualquier carácter Unicode. Pero esto significa que para acceder o crear archivos con caracteres que no están en su página de códigos debe usar std::wstring
. No hay otra manera. Esta es una extensión específica de Microsoft para std::fstream
que probablemente no se compile en otros sistemas. Si usa std :: string, solo puede utilizar nombres de archivo que solo incluyan caracteres en su página de códigos.
Sus opciones
Si solo está trabajando en Linux, probablemente no haya llegado tan lejos. Simplemente use UTF-8 en std::string
todas partes.
Si solo está trabajando en Windows, use UCS2 en std::wstring
todas partes. Algunos puristas pueden decir que use UTF8 y luego convierta cuando sea necesario, pero ¿por qué molestarse con la molestia?
Si eres multiplataforma, es un desastre ser sincero. Si intenta usar UTF-8 en todas partes en Windows, entonces debe tener mucho cuidado con los literales de cadena y la salida a la consola. Puede corromper fácilmente sus cadenas allí. Si usa std::wstring
todas partes en Linux, es posible que no tenga acceso a la versión amplia de std::fstream
, por lo que debe hacer la conversión, pero no hay riesgo de corrupción. Así que personalmente creo que esta es una mejor opción. Muchos no estarían de acuerdo, pero no estoy solo: es el camino tomado por wxWidgets, por ejemplo.
Otra opción podría ser typedef unicodestring
como std::string
en Linux y std::wstring
en Windows, y tienen una macro llamada UNI () que prefija L en Windows y en Linux nada, entonces el código
#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>
#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
std::string result;
//Call WideCharToMultiByte to do the conversion
return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
return str;
}
#endif
int main()
{
unicodestring fileName(UNI("fileName"));
std::ofstream fout;
fout.open(fileName);
std::cout << formatForConsole(fileName) << std::endl;
return 0;
}
estaría bien en cualquier plataforma, creo.
Respuestas
Entonces para responder a sus preguntas
1) Si está programando para Windows, todo el tiempo, si es multiplataforma, tal vez todo el tiempo, a menos que desee lidiar con posibles problemas de corrupción en Windows o escribir algún código con plataforma específica #ifdefs
para solucionar las diferencias, si solo usa Linux entonces nunca.
2) sí. Además en Linux, también puede usarlo para todos los Unicode. En Windows, solo puede usarlo para todos los Unicode si elige codificar manualmente con UTF-8. Pero la API de Windows y las clases estándar de C ++ esperarán std::string
que se codifique utilizando la página de códigos de la configuración regional. Esto incluye todos los ASCII más otros 128 caracteres que cambian dependiendo de la página de códigos que su computadora esté configurada para usar.
3) Creo que sí, pero si no, es solo un simple typedef de 'std :: basic_string' usando en wchar_t
lugar dechar
4) Un carácter ancho es un tipo de carácter que es más grande que el char
tipo estándar de 1 byte . En Windows es de 2 bytes, en Linux es de 4 bytes.