std :: wstring VS std :: string

No puedo entender las diferencias entre std::string y std::wstring . Sé que wstring admite caracteres anchos, como los caracteres Unicode. Tengo las siguientes preguntas:

  1. ¿Cuándo debería usar std::wstring sobre std::string ?
  2. ¿Puede std::string contener todo el conjunto de caracteres ASCII, incluidos los caracteres especiales?
  3. ¿ std::wstring compatible con todos los comstackdores populares de C ++?
  4. ¿Qué es exactamente un ” personaje ancho “?

string ? wstring ?

std::string es una basic_string plantilla en un char , y std::wstring en un wchar_t .

char vs. wchar_t

char se supone que contiene un caracter, generalmente un caracter de 1 byte. Se supone que wchar_t tiene un carácter ancho, y luego, las cosas se ponen difíciles: en Linux, un wchar_t es de 4 bytes, mientras que en Windows, es de 2 bytes

¿Qué hay de Unicode , entonces?

El problema es que ni char ni wchar_t están directamente relacionados con Unicode.

En Linux?

Tomemos un sistema operativo Linux: mi sistema Ubuntu ya es consciente de unicode. Cuando trabajo con una cadena de caracteres, está codificada de forma nativa en UTF-8 (es decir, cadena de caracteres Unicode). El siguiente código:

 #include  #include  int main(int argc, char* argv[]) { const char text[] = "olé" ; std::cout << "sizeof(char) : " << sizeof(char) << std::endl ; std::cout << "text : " << text << std::endl ; std::cout << "sizeof(text) : " << sizeof(text) << std::endl ; std::cout << "strlen(text) : " << strlen(text) << std::endl ; std::cout << "text(bytes) :" ; for(size_t i = 0, iMax = strlen(text); i < iMax; ++i) { std::cout << " " << static_cast( static_cast(text[i]) ); } std::cout << std::endl << std::endl ; // - - - const wchar_t wtext[] = L"olé" ; std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl ; //std::cout << "wtext : " << wtext << std::endl ; <- error std::cout << "wtext : UNABLE TO CONVERT NATIVELY." << std::endl ; std::wcout << L"wtext : " << wtext << std::endl; std::cout << "sizeof(wtext) : " << sizeof(wtext) << std::endl ; std::cout << "wcslen(wtext) : " << wcslen(wtext) << std::endl ; std::cout << "wtext(bytes) :" ; for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i) { std::cout << " " << static_cast( static_cast(wtext[i]) ); } std::cout << std::endl << std::endl ; return 0; } 

da como resultado el siguiente texto:

 sizeof(char) : 1 text : olé sizeof(text) : 5 strlen(text) : 4 text(bytes) : 111 108 195 169 sizeof(wchar_t) : 4 wtext : UNABLE TO CONVERT NATIVELY. wtext : ol  sizeof(wtext) : 16 wcslen(wtext) : 3 wtext(bytes) : 111 108 233 

Verá que el texto "olé" en el char está realmente construido con cuatro caracteres: 110, 108, 195 y 169 (sin contar el cero). (Te dejaré estudiar el código wchar_t como un ejercicio)

Por lo tanto, cuando se trabaja con un char en Linux, generalmente debería terminar usando Unicode sin siquiera saberlo. Y como std :: string funciona con char, std :: string ya está listo para Unicode.

Tenga en cuenta que std :: string, al igual que la cadena C API, considerará que la cadena "olé" tiene 4 caracteres, no tres. Por lo tanto, debe tener cuidado al truncar / jugar con caracteres Unicode porque está prohibida una combinación de caracteres en UTF-8.

En Windows?

En Windows, esto es un poco diferente. Win32 tuvo que soportar una gran cantidad de aplicaciones trabajando con char y en diferentes conjuntos de caracteres / páginas de códigos producidos en todo el mundo, antes del advenimiento de Unicode.

Entonces su solución fue interesante: si una aplicación funciona con char , entonces las cadenas de caracteres se codifican / imprimen / muestran en las tags de la GUI usando el juego de caracteres local / página de códigos en la máquina. Por ejemplo, "olé" sería "olé" en un Windows localizado en francés, pero sería algo diferente en un Windows localizado en cirílico ("olé" si usa Windows-1251 ). Por lo tanto, las "aplicaciones históricas" generalmente seguirán funcionando de la misma manera.

Para aplicaciones basadas en Unicode, Windows usa wchar_t , que tiene 2 bytes de ancho, y está codificado en UTF-16 , que está codificado en Unicode en caracteres de 2 bytes (o al menos, el UCS-2 más compatible, que es casi lo mismo que IIRC).

Las aplicaciones que usan char se dicen "multibyte" (porque cada glifo está compuesto de una o más wchar_t ), mientras que las aplicaciones que usan wchar_t se dicen "widechar" (porque cada glifo está compuesto por uno o dos wchar_t . Ver MultiByteToWideChar y WideCharToMultiByte Win32 conversion API para más información.

Por lo tanto, si trabaja en Windows, no quiere usar wchar_t (a menos que use un marco que lo wchar_t , como GTK + o QT ...). El hecho es que detrás de las escenas, Windows funciona con cadenas wchar_t , por lo que incluso las aplicaciones históricas tendrán sus cadenas char convertidas en wchar_t cuando usen API como SetWindowText (función de API de bajo nivel para establecer la etiqueta en una GUI de Win32).

Problemas de memoria?

UTF-32 tiene 4 bytes por caracteres, por lo que no hay mucho que agregar, solo que un texto UTF-8 y texto UTF-16 siempre usarán menos o la misma cantidad de memoria que un texto UTF-32 (y usualmente menos )

Si hay un problema de memoria, entonces debe saber que para la mayoría de los idiomas occidentales, el texto UTF-8 usará menos memoria que la misma UTF-16.

Sin embargo, para otros idiomas (chino, japonés, etc.), la memoria utilizada será la misma o mayor para UTF-8 que para UTF-16.

Con todo, UTF-16 utilizará principalmente 2 bytes por caracteres (a menos que esté tratando con algún tipo de glifos de lenguaje esotérico (Klingon? Elvish?), Mientras que UTF-8 gastará de 1 a 4 bytes.

Consulte http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 para obtener más información.

Conclusión

1. Cuando debería usar std :: wstring sobre std :: string?

En Linux? Casi nunca (§).
En Windows? Casi siempre (§).
En código multiplataforma? Depende de su kit de herramientas ...

(§): a menos que use un conjunto de herramientas / marco que diga lo contrario

2. ¿Puede std :: string contener todo el conjunto de caracteres ASCII incluyendo caracteres especiales?

Aviso: Una std :: string es adecuada para contener un búfer 'binario', ¡donde std :: wstring no lo es!

En Linux? Sí.
En Windows? Solo caracteres especiales disponibles para la configuración regional actual del usuario de Windows.

Editar (Después de un comentario de Johann Gerell ): una std :: string será suficiente para manejar todas las cadenas basadas en char (cada char es un número del 0 al 255). Pero:

  1. Se supone que ASCII va de 0 a 127. Los caracteres superiores no son ASCII.
  2. un carácter de 0 a 127 se mantendrá correctamente
  3. un carácter entre 128 y 255 tendrá un significado dependiendo de su encoding (unicode, no unicode, etc.), pero podrá contener todos los glifos Unicode siempre que estén codificados en UTF-8.

3. ¿Es std :: wstring compatible con casi todos los comstackdores populares de C ++?

En su mayoría, con la excepción de los comstackdores basados ​​en GCC que se transfieren a Windows
Funciona en mi g ++ 4.3.2 (bajo Linux), y utilicé la API Unicode en Win32 desde Visual C ++ 6.

4. ¿Qué es exactamente un personaje ancho?

En C / C ++, es un tipo de caracteres escrito wchar_t que es más grande que el tipo de carácter simple char . Se supone que debe usarse para poner caracteres internos cuyos índices (como glifos Unicode) son mayores que 255 (o 127, dependiendo ...)

Recomiendo evitar std::wstring en Windows o en otro lugar, excepto cuando lo requiera la interfaz, o en cualquier lugar cerca de las llamadas a la API de Windows y las respectivas conversiones de encoding como un azúcar sintáctico.

Mi opinión se resume en http://utf8everywhere.org de la cual soy coautor.

A menos que su aplicación esté centrada en las llamadas API, por ejemplo, principalmente en la aplicación de interfaz de usuario, la sugerencia es almacenar cadenas Unicode en std :: string y codificadas en UTF-8, realizando la conversión cerca de las llamadas API. Los beneficios descritos en el artículo superan la aparente molestia de la conversión, especialmente en aplicaciones complejas. Esto es doblemente para el desarrollo de múltiples plataformas y bibliotecas.

Y ahora, respondiendo tus preguntas:

  1. Algunas pocas razones débiles. Existe por razones históricas, donde se creía que los widechars eran la forma correcta de soportar Unicode. Ahora se usa para interfaces API que prefieren cadenas UTF-16. Los uso solo en las inmediaciones de tales llamadas API.
  2. Esto no tiene nada que ver con std :: string. Puede contener cualquier encoding que pongas en él. La única pregunta es cómo trata su contenido. Mi recomendación es UTF-8, por lo que será capaz de contener todos los caracteres Unicode correctamente. Es una práctica común en Linux, pero creo que los progtwigs de Windows también deberían hacerlo.
  3. No.
  4. El personaje ancho es un nombre confuso. En los primeros días de Unicode, existía la creencia de que el carácter se puede codificar en dos bytes, de ahí el nombre. Hoy, representa “cualquier parte del personaje que tenga dos bytes de longitud”. UTF-16 se ve como una secuencia de dichos pares de bytes (también conocidos como caracteres anchos). Un personaje en UTF-16 toma uno o dos pares.

Entonces, cada lector aquí debería tener una comprensión clara de los hechos, la situación. Si no, entonces debes leer la respuesta extraordinariamente completa de paercebal [por cierto, ¡gracias!].

Mi conclusión pragmática es sorprendentemente simple: todo lo que C ++ (y STL) “encoding de caracteres” está sustancialmente roto e inútil. La culpa es de Microsoft o no, eso no ayudará de todos modos.

Mi solución, después de una investigación profunda, mucha frustración y las experiencias consiguientes, es la siguiente:

  1. Acepte, que usted debe ser responsable por su propia encoding y conversión (y verá que gran parte es bastante trivial)

  2. use std :: string para cualquier cadena codificada UTF-8 (solo un typedef std::string UTF8String )

  3. acepta que un objeto UTF8String es simplemente un contenedor tonto, pero barato. Nunca acceda y / o manipule caracteres en él directamente (sin buscar, reemplazar, etc.). Podrías, pero realmente realmente, ¡realmente no quieres perder el tiempo escribiendo algoritmos de manipulación de texto para cadenas de múltiples bytes! Incluso si otras personas ya hicieron cosas tan estúpidas, ¡no hagas eso! ¡Déjalo ser! (Bueno, hay escenarios donde tiene sentido … solo use la biblioteca de la ICU para eso).

  4. use std :: wstring para cadenas codificadas UCS-2 ( typedef std::wstring UCS2String ) – esto es un compromiso, y una concesión al desastre que introdujo la API de WIN32). UCS-2 es suficiente para la mayoría de nosotros (más sobre eso más adelante …).

  5. use instancias de UCS2String siempre que se requiera un acceso de carácter por carácter (lectura, manipulación, etc.). Cualquier procesamiento basado en caracteres debe hacerse en una representación no multibyte. Es simple, rápido, fácil.

  6. agregue dos funciones de utilidad para convertir entre UTF-8 y UCS-2:

     UCS2String ConvertToUCS2( const UTF8String &str ); UTF8String ConvertToUTF8( const UCS2String &str ); 

Las conversiones son sencillas, Google debería ayudar aquí …

Eso es. Use UTF8String donde la memoria sea valiosa y para todas las E / S UTF-8. Use UCS2String donde la cadena debe ser analizada y / o manipulada. Puede convertir entre esas dos representaciones en cualquier momento.

Alternativas y mejoras

  • las conversiones de y a codificaciones de caracteres de un solo byte (p. ej. ISO-8859-1) pueden realizarse con la ayuda de tablas de traducción simples, por ejemplo, const wchar_t tt_iso88951[256] = {0,1,2,...}; y el código apropiado para la conversión a y desde UCS2.

  • si UCS-2 no es suficiente, cambie a UCS-4 ( typedef std::basic_string UCS2String )

ICU u otras bibliotecas Unicode?

Para cosas avanzadas.

  1. Cuando desee tener caracteres anchos almacenados en su cadena. wide depende de la implementación. Visual C ++ tiene un valor predeterminado de 16 bits si recuerdo correctamente, mientras que GCC se establece de forma predeterminada según el objective. Tiene 32 bits de largo aquí. Tenga en cuenta que wchar_t (tipo de caracteres anchos) no tiene nada que ver con unicode. Simplemente se garantiza que puede almacenar todos los miembros del conjunto de caracteres más grande que la implementación admite en sus configuraciones regionales, y al menos siempre que sea char. Puede almacenar cadenas unicode bien en std::string usando la encoding utf-8 también. Pero no comprenderá el significado de los puntos de código Unicode. Así que str.size() no le dará la cantidad de caracteres lógicos en su cadena, sino simplemente la cantidad de elementos char o wchar_t almacenados en esa cadena / wstring. Por esa razón, la gente del contenedor Glib::ustring / glib C ++ ha desarrollado una clase Glib::ustring que puede manejar utf-8.

    Si su wchar_t tiene 32 bits de longitud, puede usar utf-32 como una encoding Unicode, y puede almacenar y manejar cadenas Unicode usando una encoding fija (utf-32 es de longitud fija). Esto significa que la función s.size() su wstring devolverá la cantidad correcta de elementos wchar_t y caracteres lógicos.

  2. Sí, char siempre tiene al menos 8 bits de largo, lo que significa que puede almacenar todos los valores ASCII.
  3. Sí, todos los principales comstackdores lo admiten.

Con frecuencia utilizo std :: string para mantener los caracteres utf-8 sin ningún problema. Recomiendo encarecidamente hacer esto cuando interactúas con API que también usan utf-8 como el tipo de cadena nativa.

Por ejemplo, uso utf-8 al conectar mi código con el intérprete Tcl.

La principal advertencia es la longitud de std :: string, ya no es la cantidad de caracteres en la cadena.

  1. Cuando desee almacenar caracteres “anchos” (Unicode).
  2. Sí: 255 de ellos (excluyendo 0).
  3. Sí.
  4. Aquí hay un artículo introductorio: http://www.joelonsoftware.com/articles/Unicode.html

Las aplicaciones que no están satisfechas con solo 256 caracteres diferentes tienen la opción de usar caracteres anchos (más de 8 bits) o una encoding de longitud variable (una encoding multibyte en terminología C ++) como UTF-8. Los caracteres anchos generalmente requieren más espacio que una encoding de longitud variable, pero son más rápidos de procesar. Las aplicaciones de varios idiomas que procesan grandes cantidades de texto generalmente usan caracteres anchos al procesar el texto, pero lo convierten a UTF-8 cuando lo guardan en el disco.

La única diferencia entre una string y un wstring es el tipo de datos de los caracteres que almacenan. Una cadena almacena caracteres cuyo tamaño garantizado es de al menos 8 bits, por lo que puede usar cadenas para procesar, por ejemplo, texto ASCII, ISO-8859-15 o UTF-8. El estándar no dice nada sobre el conjunto de caracteres o la encoding.

Prácticamente todos los comstackdores usan un conjunto de caracteres cuyos primeros 128 caracteres corresponden con ASCII. Este es también el caso de los comstackdores que usan encoding UTF-8. Lo importante a tener en cuenta cuando se usan cadenas en UTF-8 u otra encoding de longitud variable es que los índices y longitudes se miden en bytes, no en caracteres.

El tipo de datos de una cadena ws es wchar_t , cuyo tamaño no está definido en la norma, excepto que debe ser al menos tan grande como una char, generalmente 16 bits o 32 bits. wstring se puede utilizar para procesar texto en la implementación de encoding de caracteres anchos definida. Debido a que la encoding no está definida en el estándar, no es fácil convertir cadenas y wstrings. Tampoco se puede suponer que wstrings tenga una encoding de longitud fija.

Si no necesita soporte multilingüe, puede usar cadenas normales. Por otro lado, si está escribiendo una aplicación gráfica, a menudo sucede que la API solo admite caracteres anchos. Entonces es probable que desee utilizar los mismos caracteres anchos al procesar el texto. Tenga en cuenta que UTF-16 es una encoding de longitud variable, lo que significa que no puede asumir length() para devolver el número de caracteres. Si la API utiliza una encoding de longitud fija, como UCS-2, el procesamiento se vuelve fácil. La conversión entre caracteres anchos y UTF-8 es difícil de hacer de forma portátil, pero, una vez más, su API de interfaz de usuario probablemente sea compatible con la conversión.

  1. cuando quieres usar cadenas Unicode y no solo ascii, útiles para la internacionalización
  2. sí, pero no funciona bien con 0
  3. no consciente de ninguno que no lo haga
  4. el carácter ancho es la forma específica del comstackdor de manejar la representación de longitud fija de un carácter Unicode, para MSVC es un carácter de 2 bytes, para gcc entiendo que es de 4 bytes. y un +1 para http://www.joelonsoftware.com/articles/Unicode.html

1) Como menciona Greg, wstring es útil para la internacionalización, es cuando lanzarás tu producto en otros idiomas que no sean el inglés

4) Mira esto para ver el personaje ancho http://en.wikipedia.org/wiki/Wide_character

Una buena pregunta! Creo que la CODIFICACIÓN DE DATOS (a veces CHARSET también está involucrada) es un MECANISMO DE EXPRESIÓN DE MEMORIA para guardar datos en un archivo o transferir datos a través de la red, así que respondo esta pregunta como:

1. ¿Cuándo debería usar std :: wstring sobre std :: string?

Si la plataforma de progtwigción o la función API es de un solo byte, y queremos procesar o analizar algunos datos unicode, por ejemplo, leer desde el archivo .REG de Windows o la secuencia de 2 bytes de la red, debemos declarar que la variable std :: wstring es fácil procesarlos. por ejemplo: wstring ws = L “中国 a” (memoria de 6 octetos: 0x4E2D 0x56FD 0x0061), podemos usar ws [0] para obtener el carácter ‘中’ y ws [1] para obtener el carácter ‘国’ y ws [2] para obtener el carácter ‘a’, etc.

2.Can std :: string contiene todo el conjunto de caracteres ASCII, incluidos los caracteres especiales?

Sí. Pero fíjate: American ASCII, significa que cada octeto 0x00 ~ 0xFF representa un solo carácter, incluyendo texto imprimible como “123abc & * _ &” y dijiste especial, sobre todo imprímelo como ‘.’ evite confundir editores o terminales. Y algunos otros países amplían su propio juego de caracteres “ASCII”, por ejemplo, chino, usan 2 octetos para representar un personaje.

3. ¿Es std :: wstring compatible con todos los comstackdores populares de C ++?

Quizás, o en su mayoría. He usado: VC ++ 6 y GCC 3.3, SÍ

4. ¿Qué es exactamente un “personaje ancho”?

el carácter ancho indica principalmente el uso de 2 octetos u 4 octetos para contener los caracteres de todos los países. 2 octetos UCS2 es una muestra representativa, y además, por ejemplo, ‘a’ en inglés, su memoria es de 2 octetos de 0x0061 (frente a ASCII ‘la memoria de a es 1 octeto 0x61)

Aquí hay algunas muy buenas respuestas, 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 std::string encoding UTF-8 en todas partes. En Windows / VS se vuelve más complejo. Aquí está el por qué. Windows espera que las cadenas almacenadas usando char s se codifiquen utilizando la página de códigos de configuración regional. Casi siempre es el conjunto de caracteres ASCII seguido de otros 128 caracteres especiales según su ubicación. Permítanme decir que no solo al usar la API de Windows, hay otros tres lugares importantes donde estas cadenas interactúan con C ++ estándar. Estos son literales de cadena, salida a std::cout usando << y pasando un nombre de archivo a std::fstream .

Aquí estaré al frente de que soy un progtwigdor, no un 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 tal aquí. No estoy seguro de qué Windows usa, pero generalmente tampoco necesito saberlo. He declarado UCS2 en esta respuesta, así que lo siento de antemano si molesto a alguien por mi ignorancia sobre este asunto y estoy feliz de cambiarlo si tengo problemas.

Literales de cadenas

Si ingresa los 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 encoding de caracteres en función de 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 si el personaje cambiará también.

If you enter any string literals that cannot be represented by your codepage then VS will ask you to save the file as Unicode. The file will then be encoded as UTF-8. This means that all Non ASCII characters (including those which are on your codepage) will be represented by 2 or more bytes. This means if you give your source to someone else the source will look the same. However, before passing the source to the compiler, VS converts the UTF-8 encoded text to code page encoded text and any characters missing from the code page are replaced with ? .

The only way to guarantee correctly representing a Unicode string literal in VS is to precede the string literal with an L making it a wide string literal. In this case VS will convert the UTF-8 encoded text from the file into UCS2. You then need to pass this string literal into a std::wstring constructor or you need to convert it to utf-8 and put it in a std::string . Or if you want you can use the Windows API functions to encode it using your code page to put it in a std::string , but then you may as well have not used a wide string literal.

std::cout

When outputting to the console using << you can only use std::string , not std::wstring and the text must be encoded using your locale codepage. If you have a std::wstring then you must convert it using one of the Windows API functions and any characters not on your codepage get replaced by ? (maybe you can change the character, I can't remember).

std::fstream filenames

Windows OS uses UCS2/UTF-16 for its filenames so whatever your codepage, you can have files with any Unicode character. But this means that to access or create files with characters not on your codepage you must use std::wstring . No hay otra manera. This is a Microsoft specific extension to std::fstream so probably won't compile on other systems. If you use std::string then you can only utilise filenames that only include characters on your codepage.

Your options

If you are just working on Linux then you probably didn't get this far. Just use UTF-8 std::string everywhere.

If you are just working on Windows just use UCS2 std::wstring everywhere. Some purists may say use UTF8 then convert when needed, but why bother with the hassle.

If you are cross platform then it's a mess to be frank. If you try to use UTF-8 everywhere on Windows then you need to be really careful with your string literals and output to the console. You can easily corrupt your strings there. If you use std::wstring everywhere on Linux then you may not have access to the wide version of std::fstream , so you have to do the conversion, but there is no risk of corruption. So personally I think this is a better option. Many would disagree, but I'm not alone - it's the path taken by wxWidgets for example.

Another option could be to typedef unicodestring as std::string on Linux and std::wstring on Windows, and have a macro called UNI() which prefixes L on Windows and nothing on Linux, then the code

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

would be fine on either platform I think.

Respuestas

So To answer your questions

1) If you are programming for Windows, then all the time, if cross platform then maybe all the time, unless you want to deal with possible corruption issues on Windows or write some code with platform specific #ifdefs to work around the differences, if just using Linux then never.

2)Yes. In addition on Linux you can use it for all Unicode too. On Windows you can only use it for all unicode if you choose to manually encode using UTF-8. But the Windows API and standard C++ classes will expect the std::string to be encoded using the locale codepage. This includes all ASCII plus another 128 characters which change depending on the codepage your computer is setup to use.

3)I believe so, but if not then it is just a simple typedef of a 'std::basic_string' using wchar_t instead of char

4)A wide character is a character type which is bigger than the 1 byte standard char type. On Windows it is 2 bytes, on Linux it is 4 bytes.

When should you NOT use wide-characters?

When you’re writing code before the year 1990.

Obviously, I’m being flip, but really, it’s the 21st century now. 127 characters have long since ceased to be sufficient. Yes, you can use UTF8, but why bother with the headaches?