¿TCHAR sigue siendo relevante?

87

Soy nuevo en la programación de Windows y después de leer el libro de Petzold me pregunto:

¿Sigue siendo una buena práctica usar el TCHARtipo y la _T()función para declarar cadenas o si debería usar las cadenas wchar_ty L""en el nuevo código?

Apuntaré solo a Windows 2000 y versiones posteriores y mi código será i18n desde el inicio.

Fábio
fuente

Respuestas:

15

Todavía usaría la sintaxis TCHAR si estuviera haciendo un nuevo proyecto hoy. No hay mucha diferencia práctica entre usarlo y la sintaxis WCHAR, y prefiero un código que sea explícito en cuanto al tipo de carácter. Dado que la mayoría de las funciones de API y los objetos auxiliares toman / usan tipos TCHAR (por ejemplo: CString), tiene sentido usarlo. Además, le brinda flexibilidad si decide usar el código en una aplicación ASCII en algún momento, o si Windows alguna vez evoluciona a Unicode32, etc.

Si decide seguir la ruta WCHAR, sería explícito al respecto. Es decir, use CStringW en lugar de CString y ejecute macros al convertir a TCHAR (por ejemplo: CW2CT).

Esa es mi opinión, de todos modos.

Mella
fuente
De hecho, eso es lo que seguirá funcionando cuando la codificación de caracteres finalmente se cambie "de nuevo".
Medinoc
11
¿Prefieres un código que sea explícito en cuanto al tipo de carácter y, por lo tanto, usas un tipo que a veces es esto y a veces aquello? Muy persuasivo.
Deduplicador
4
−1 por la inconsistencia notada por @Deduplicator, y por el consejo de pago negativo de usar una macro que puede ser lo que sea (y generalmente no se probará para más de un valor específico).
Saludos y hth. - Alf
90

La respuesta corta: NO .

Como todos los demás ya escribieron, muchos programadores todavía usan TCHAR y las funciones correspondientes. En mi humilde opinión, todo el concepto fue una mala idea . El procesamiento de cadenas UTF-16 es muy diferente al procesamiento simple de cadenas ASCII / MBCS. Si usa los mismos algoritmos / funciones con ambos (¡esto es en lo que se basa la idea de TCHAR!), Obtendrá un rendimiento muy malo en la versión UTF-16 si está haciendo un poco más que una simple concatenación de cadenas (como análisis, etc.). La razón principal son los sustitutos .

Con la única excepción cuando realmente tiene que compilar su aplicación para un sistema que no es compatible con Unicode, no veo ninguna razón para usar este bagaje del pasado en una nueva aplicación.

Sascha
fuente
6
Dato curioso: UTF-16 no siempre estuvo presente en la plataforma NT. Los puntos de código sustitutos se introdujeron con Unicode 2.0, en 1996, que fue el mismo año en que se lanzó NT 4. Hasta el IIRC, (incluido) Windows 2000, todas las versiones de NT usaban UCS-2, efectivamente un subconjunto de UTF-16 que asumía que cada carácter era representable con un punto de código (es decir, sin sustitutos).
0xC0000022L
3
por cierto, aunque estoy de acuerdo en que TCHARno debería usarse más, no estoy de acuerdo en que esto fue una mala idea. También creo que si eliges ser explícito en lugar de usar TCHAR, debes ser explícito en todas partes . Es decir, tampoco use funciones con TCHAR/ _TCHAR(como _tmain) en su declaración. En pocas palabras: sea coherente. +1, todavía.
0xC0000022L
3
Era una buena idea cuando se introdujo, pero debería ser irrelevante en el nuevo código.
Adrian McCarthy
4
Usted tergiversa, para qué TCHARse introdujeron inicialmente: Para facilitar el desarrollo de código para las versiones de Windows basadas en Win 9x y Windows NT. En ese momento, la implementación de UTF-16 de Windows NT era UCS-2, y los algoritmos para el análisis / manipulación de cadenas eran idénticos. No hubo sustitutos. E incluso con sustitutos, los algoritmos para DBCS (la única codificación MBCS admitida para Windows) y UTF-16 son los mismos: en cualquier codificación, un punto de código consta de una o dos unidades de código.
Inspectable
Supongamos que quiero usar FormatMessage () para convertir un valor de WSAGetLastError () en algo imprimible. La documentación de WSAGetLastError () dice que toma LPTSTR como puntero al búfer. Realmente no tengo muchas opciones más que usar TCHAR, ¿no?
Edward Falk
80

Tengo que estar de acuerdo con Sascha. La premisa subyacente de TCHAR/ _T()/ etc. es que puede escribir una aplicación basada en "ANSI" y luego mágicamente darle soporte Unicode definiendo una macro. Pero esto se basa en varias suposiciones erróneas:

Que construya activamente versiones MBCS y Unicode de su software

De lo contrario, se equivocará y utilizará char*cuerdas normales en muchos lugares.

Que no use escapes de barra invertida no ASCII en literales _T ("...")

A menos que su codificación "ANSI" sea ISO-8859-1, el resultado char*y los wchar_t*literales no representarán los mismos caracteres.

Que las cadenas UTF-16 se utilizan como cadenas "ANSI"

Ellos no están. Unicode introduce varios conceptos que no existen en la mayoría de las codificaciones de caracteres heredadas. Sustitutos. Combinando personajes. Normalización. Reglas de mayúsculas y minúsculas condicionales y sensibles al idioma.

Y quizás lo más importante, el hecho de que UTF-16 rara vez se guarda en disco o se envía a través de Internet: UTF-8 tiende a ser preferido para la representación externa.

Que tu aplicación no usa Internet

(Ahora, esto puede ser una suposición válida para su software, pero ...)

La web se ejecuta en UTF-8 y una gran cantidad de codificaciones más raras . El TCHARconcepto solo reconoce dos: "ANSI" (que no puede ser UTF-8 ) y "Unicode" (UTF-16). Puede ser útil para hacer que sus llamadas API de Windows sean compatibles con Unicode, pero es muy inútil para hacer que sus aplicaciones web y de correo electrónico sean compatibles con Unicode.

Que no use bibliotecas que no sean de Microsoft

Nadie más lo usa TCHAR. Poco usa std::stringy UTF-8. SQLite tiene versiones UTF-8 y UTF-16 de su API, pero no TCHAR. TCHARni siquiera está en la biblioteca estándar, así que no, a std::tcoutmenos que quieras definirlo tú mismo.

Lo que recomiendo en lugar de TCHAR

Olvídese de que existen codificaciones "ANSI", excepto cuando necesita leer un archivo que no es válido en UTF-8. Olvídate TCHARtambién. Llame siempre a la versión "W" de las funciones de la API de Windows. #define _UNICODEsolo para asegurarse de no llamar accidentalmente a una función "A".

Utilice siempre codificaciones UTF para cadenas: UTF-8 para charcadenas y UTF-16 (en Windows) o UTF-32 (en sistemas similares a Unix) para wchar_tcadenas. typedef UTF16y UTF32tipos de personajes para evitar diferencias de plataforma.

dan04
fuente
6
2012 convocatoria: aún quedan aplicaciones por mantener sin #define _UNICODEni siquiera ahora. Fin de transmisión :)
0xC0000022L
12
@ 0xC0000022L la pregunta era sobre el nuevo código. Cuando mantiene un código antiguo, obviamente tiene que trabajar con el entorno para el que está escrito el código. Si mantiene una aplicación COBOL, entonces no importa si COBOL es un buen idioma o no, está atascado con él. Y si está manteniendo una aplicación que se basa en TCHAR, no importa si fue una buena decisión o no, está atascado con ella.
jalf
2
De hecho, TCHAR no es útil a menos que esté en COBOL)
Pavel Radzivilovsky
1
_UNICODEcontrola cómo se resuelven las asignaciones de texto genérico en el CRT. Si no desea llamar a la versión ANSI de una API de Windows, debe definir UNICODE.
Inspectable
18

Si se pregunta si todavía está en práctica, entonces sí, todavía se usa bastante. Nadie verá su código de manera extraña si usa TCHAR y _T (""). El proyecto en el que estoy trabajando ahora se está convirtiendo de ANSI a Unicode, y vamos por la ruta portátil (TCHAR).

Sin embargo...

Mi voto sería olvidar todas las macros portátiles ANSI / UNICODE (TCHAR, _T (""), y todas las llamadas _tXXXXXX, etc ...) y simplemente asumir unicode en todas partes. Realmente no veo el sentido de ser portátil si nunca necesitará una versión ANSI. Usaría todas las funciones y tipos de caracteres amplios directamente. Anteponga todos los literales de cadena con una L.

Cerdo hormiguero
fuente
3
Puede escribir algún código que desee usar en otro lugar donde necesite una versión ANSI, o (como dijo Nick) Windows podría pasar a DCHAR o lo que sea, así que sigo pensando que es una muy buena idea ir con TCHAR en lugar de WCHAR.
Arca
Dudo que Windows cambie alguna vez a UTF-32.
dan04
7
-1 para la recomendación UTF-16. No solo esto crea un código no portátil (centrado en Windows), que es inaceptable para las bibliotecas, aunque puede usarse para los casos más simples como el código de la interfaz de usuario, no es eficiente incluso en Windows. utf8everywhere.org
Pavel Radzivilovsky
11

El artículo Introducción a la programación de Windows en MSDN dice

Las nuevas aplicaciones siempre deben llamar a las versiones Unicode (de la API).

Las macros TEXT y TCHAR son menos útiles hoy en día, porque todas las aplicaciones deberían usar Unicode.

Me quedaría con wchar_ty L"".

Steven
fuente
4
Steven, estás citando un texto escrito por alguien que no comprende el significado de la palabra 'Unicode'. Es uno de esos documentos desafortunados de la época de la confusión UCS-2.
Pavel Radzivilovsky
2
@PavelRadzivilovsky: El documento fue escrito para un sistema, donde Unicode y UTF-16LE se usan comúnmente de manera intercambiable. Si bien es técnicamente inexacto, no obstante es inequívoco. Esto también se señala explícitamente en la introducción del mismo texto: "Windows representa caracteres Unicode usando codificación UTF-16 [...]" .
IInspectable
11

Me gustaría sugerir un enfoque diferente (ninguno de los dos).

Para resumir, use char * y std :: string, asumiendo la codificación UTF-8, y realice las conversiones a UTF-16 solo cuando ajuste las funciones de la API.

Puede encontrar más información y justificación de este enfoque en los programas de Windows en http://www.utf8everywhere.org .

Pavel Radzivilovsky
fuente
@PavelRadzivilovsky, al implementar su sugerencia en una aplicación VC ++, ¿estableceríamos el conjunto de caracteres de VC ++ en 'Ninguno' o 'Multibyte (MBCS)'? La razón por la que pregunto es que acabo de instalar Boost :: Locale y el juego de caracteres predeterminado era MBCS. FWIW, mi aplicación ASCII pura se configuró en 'Ninguno' y ahora la configuré en 'MBCS' (ya que usaré Boost :: Locale en ella) y funciona bien. Por favor avise.
Caroline Beltran
Como recomienda utf8everywhere, lo establecería en 'Usar conjunto de caracteres Unicode'. Estos anuncios son más seguros, pero no son obligatorios. El autor de Boost :: locale es un tipo muy inteligente, aunque estoy seguro de que hizo lo correcto.
Pavel Radzivilovsky
1
El mantra UTF-8 Everywhere no se convertirá en la solución correcta, solo porque se repite con más frecuencia. UTF-8 es sin duda una codificación atractiva para la serialización (por ejemplo, archivos o sockets de red), pero en Windows suele ser más apropiado almacenar datos de caracteres utilizando la codificación UTF-16 nativa internamente y convertirlos en el límite de la aplicación. Una razón es que UTF-16 es la única codificación que se puede convertir inmediatamente a cualquier otra codificación compatible. Este no es el caso de UTF-8.
IInspectable
"..UTF-16 es la única codificación que se puede convertir inmediatamente a cualquier otra codificación compatible". ¿Qué quieres decir? ¿Cuál es el problema para convertir la codificación UTF-8 a cualquier otra cosa?
Pavel Radzivilovsky
1
No entiendo. Para cualquier otra cosa, ¿como qué? Por ejemplo, UCS-4? Por qué no? Parece muy fácil, todo algoritmo numérico ..
Pavel Radzivilovsky
7

TCHAR/ WCHARpodría ser suficiente para algunos proyectos heredados. Pero para nuevas aplicaciones, diría NO .

Todas estas TCHAR/ WCHARcosas están ahí por razones históricas. TCHARproporciona una forma (disfraz) aparentemente ordenada para cambiar entre codificación de texto ANSI (MBCS) y codificación de texto Unicode (UTF-16). En el pasado, las personas no entendían la cantidad de caracteres de todos los idiomas del mundo. Asumieron que 2 bytes eran suficientes para representar todos los caracteres y, por lo tanto, tenían un esquema de codificación de caracteres de longitud fija WCHAR. Sin embargo, esto ya no es cierto después del lanzamiento de Unicode 2.0 en 1996 .

Es decir: no importa cuál use en CHAR/ WCHAR/ TCHAR, la parte de procesamiento de texto en su programa debería poder manejar caracteres de longitud variable para internacionalización.

Entonces, en realidad, debe hacer más que elegir uno de CHAR/ WCHAR/ TCHARpara programar en Windows:

  1. Si su aplicación es pequeña y no implica procesamiento de texto (es decir, simplemente pasar la cadena de texto como argumentos), siga adelante WCHAR. Ya que de esta manera es más fácil trabajar con WinAPI con soporte Unicode.
  2. De lo contrario, sugeriría usar UTF-8 como codificación interna y almacenar textos en cadenas de caracteres o std :: cadena. Y conviértalos en UTF-16 al llamar a WinAPI. UTF-8 es ahora la codificación dominante y hay muchas bibliotecas y herramientas útiles para procesar cadenas UTF-8.

Consulte este maravilloso sitio web para leer más en profundidad: http://utf8everywhere.org/

Leopardo
fuente
2
"UTF-8 es ahora la codificación dominante" - Esto resultó mal al omitir la segunda parte de la cita ( "para la World Wide Web" ). Para las aplicaciones de escritorio, la codificación de caracteres nativa más utilizada probablemente siga siendo UTF-16. Windows lo usa, Mac OS X también, y también los tipos de cadenas de .NET y Java. Eso representa una enorme cantidad de código. No me malinterpretes, no hay nada de malo en UTF-8 para la serialización. Pero la mayoría de las veces (especialmente en Windows), encontrará que usar UTF-16 internamente es más apropiado.
Inspectable
4

Si, absolutamente; al menos para la macro _T. Sin embargo, no estoy tan seguro de las cosas de carácter amplio.

La razón es para soportar mejor WinCE u otras plataformas de Windows no estándar. Si está 100% seguro de que su código permanecerá en NT, entonces probablemente pueda usar declaraciones regulares de C-string. Sin embargo, es mejor tender hacia el enfoque más flexible, ya que es mucho más fácil #definir esa macro en una plataforma que no es de Windows en comparación con pasar por miles de líneas de código y agregarlo en todas partes en caso de que necesite portar alguna biblioteca a Windows Mobile.

Nik Reiman
fuente
1
WinCE usa cadenas wchar_t de 16 bits como Win32. Tenemos una gran base de código que se ejecuta en WinCE y Win32 y nunca usamos TCHAR.
mhenry1384
2

En mi humilde opinión, si hay TCHAR en su código, está trabajando en el nivel incorrecto de abstracción.

Usar cualquier tipo de cadena es más conveniente para usted cuando se trata de procesamiento de texto - esto se espera que sea algo Unicode apoyo, pero eso depende de ti. Realice la conversión en los límites de la API del sistema operativo según sea necesario.

Cuando trabaje con rutas de archivo, cree su propio tipo personalizado en lugar de usar cadenas. Esto le permitirá separadores de ruta independientes del sistema operativo, le dará una interfaz más fácil de codificar que la concatenación y división manual de cadenas, y será mucho más fácil de adaptar a diferentes sistemas operativos (ansi, ucs-2, utf-8, lo que sea) .

snemarch
fuente
Unicode tiene al menos tres codificaciones actuales (UTF-8, UTF-16, UTF-32) y una codificación obsoleta (UCS-2, un subconjunto de lo que ahora es UTF-16). ¿A cuál te refieres? Aunque me gusta el resto de las sugerencias +1
0xC0000022L
2

Las únicas razones que veo para usar otra cosa que no sea el WCHAR explícito son la portabilidad y la eficiencia.

Si desea que su ejecutable final sea lo más pequeño posible, use char.

Si no le importa el uso de RAM y desea que la internacionalización sea tan fácil como una simple traducción, use WCHAR.

Si desea que su código sea flexible, use TCHAR.

Si solo planea usar los caracteres latinos, también puede usar las cadenas ASCII / MBCS para que su usuario no necesite tanta RAM.

Para las personas que son "i18n desde el principio", ahórrese el espacio del código fuente y simplemente use todas las funciones Unicode.

Trololol
fuente
-1

Solo agregando a una vieja pregunta:

NO

Vaya a iniciar un nuevo proyecto CLR C ++ en VS2010. Los mismos Microsoft usan L"Hello World"', dijo Nuff.

kizzx2
fuente
13
CLR es un entorno muy diferente al código no administrado. Eso no es un argumento.
Cody Gray
3
Incluso Microsoft comete errores.
Pavel Radzivilovsky
6
-1 La pregunta está etiquetada Cy C++. Las respuestas siempre pueden ser eliminadas por sus respectivos autores. Este sería un buen momento para utilizar esa disposición.
Inenspectable