O TCHAR ainda é relevante?

87

Eu sou novo na programação do Windows e depois de ler o livro Petzold, eu me pergunto:

ainda é uma boa prática usar o TCHARtipo e a _T()função para declarar strings ou se eu deveria apenas usar as strings wchar_te L""no novo código?

Visarei apenas o Windows 2000 e superior e meu código será i18n desde a inicialização.

Fábio
fonte

Respostas:

15

Eu ainda usaria a sintaxe TCHAR se estivesse fazendo um novo projeto hoje. Não há muita diferença prática entre usá-lo e a sintaxe WCHAR, e eu prefiro um código que seja explícito quanto ao tipo de caractere. Como a maioria das funções API e objetos auxiliares aceitam / usam tipos TCHAR (por exemplo: CString), faz sentido usá-los. Além disso, oferece flexibilidade se você decidir usar o código em um aplicativo ASCII em algum momento ou se o Windows evoluir para Unicode32, etc.

Se você decidir seguir a rota WCHAR, eu seria explícito sobre isso. Ou seja, use CStringW em vez de CString e converta macros ao converter para TCHAR (por exemplo: CW2CT).

Essa é minha opinião, de qualquer maneira.

usuario
fonte
Na verdade, é isso que ainda funcionará quando a codificação do caractere for eventualmente alterada '' novamente ''.
Medinoc de
11
Você prefere um código que seja explícito quanto ao tipo de caractere e, portanto, usa um tipo que às vezes é isso e às vezes aquilo? Muito persuasivo.
Deduplicator
4
-1 para a inconsistência observada por @Deduplicator, e para o conselho de compensação negativa para usar uma macro que pode ser qualquer (e geralmente não será testada para mais de um valor específico).
Saúde e hth. - Alf
90

A resposta curta: NÃO .

Como todos os outros já escritos, muitos programadores ainda usam TCHARs e as funções correspondentes. Na minha humilde opinião, todo o conceito foi uma má ideia . O processamento de strings UTF-16 é muito diferente do processamento simples de strings ASCII / MBCS. Se você usar os mesmos algoritmos / funções com ambos (é nisso que se baseia a ideia do TCHAR!), Você obterá um desempenho muito ruim na versão UTF-16 se estiver fazendo um pouco mais do que simples concatenação de strings (como análise, etc.). O principal motivo são os substitutos .

Com a única exceção quando você realmente precisa compilar seu aplicativo para um sistema que não oferece suporte a Unicode, não vejo razão para usar essa bagagem do passado em um novo aplicativo.

Sascha
fonte
6
Curiosidade: o UTF-16 nem sempre existia na plataforma NT. Os surrogate code points foram introduzidos com o Unicode 2.0, em 1996, no mesmo ano em que o NT 4 foi lançado. Até o IIRC, (incluindo) o Windows 2000, todas as versões do NT usavam UCS-2, efetivamente um subconjunto do UTF-16 que assumia que cada caractere era representável com um ponto de código (ou seja, sem substitutos).
0xC0000022L
3
aliás, embora eu concorde que TCHARnão deve ser mais usado, discordo que isso foi uma má ideia. Também acho que se você escolher ser explícito em vez de usar, TCHARdeve ser explícito em todos os lugares . Ou seja, não use funções com TCHAR/ _TCHAR(como _tmain) em sua declaração. Simplificando: seja consistente. 1, ainda.
0xC0000022L
3
Foi uma boa ideia quando foi introduzido, mas deve ser irrelevante no novo código.
Adrian McCarthy
4
Você deturpou o que TCHARfoi inicialmente introduzido: Para facilitar o desenvolvimento de código para versões baseadas em Win 9x e Windows NT do Windows. Naquela época, a implementação UTF-16 do Windows NT era UCS-2 e os algoritmos para análise / manipulação de strings eram idênticos. Não houve substitutos. E mesmo com substitutos, algoritmos para DBCS (a única codificação MBCS com suporte para Windows) e UTF-16 são os mesmos: em qualquer codificação, um ponto de código consiste em uma ou duas unidades de código.
Inspectável
Suponha que eu queira usar FormatMessage () para converter um valor de WSAGetLastError () em algo imprimível. A documentação para WSAGetLastError () diz que leva LPTSTR como o ponteiro para o buffer. Eu realmente não tenho muita escolha a não ser usar o TCHAR, não?
Edward Falk
80

Eu tenho que concordar com Sascha. A premissa subjacente de TCHAR/ _T()/ etc. é que você pode escrever um aplicativo baseado em "ANSI" e, em seguida, magicamente dar a ele suporte Unicode definindo uma macro. Mas isso se baseia em várias suposições erradas:

Que você construa ativamente as versões MBCS e Unicode de seu software

Caso contrário, você vai escorregar e usar comuns char*cordas em muitos lugares.

Que você não use escapes de barra invertida não ASCII em literais _T ("...")

A menos que sua codificação "ANSI" seja ISO-8859-1, o resultado char*e os wchar_t*literais não representarão os mesmos caracteres.

Que strings UTF-16 são usadas como strings "ANSI"

Eles não são. O Unicode apresenta vários conceitos que não existem na maioria das codificações de caracteres legados. Substitutos. Combinando personagens. Normalização. Regras de capitalização condicionais e sensíveis ao idioma.

E talvez o mais importante, o fato de que UTF-16 raramente é salvo em disco ou enviado pela Internet: UTF-8 tende a ser preferido para representação externa.

Que seu aplicativo não usa a Internet

(Agora, esta pode ser uma suposição válida para o seu software, mas ...)

A web roda em UTF-8 e uma infinidade de codificações mais raras . O TCHARconceito reconhece apenas dois: "ANSI" (que não pode ser UTF-8 ) e "Unicode" (UTF-16). Pode ser útil para tornar suas chamadas de API do Windows compatíveis com Unicode, mas é absolutamente inútil para tornar seus aplicativos de web e de email compatíveis com Unicode.

Que você não use bibliotecas que não sejam da Microsoft

Ninguém mais usa TCHAR. Poco usa std::stringe UTF-8. SQLite tem versões UTF-8 e UTF-16 de sua API, mas não TCHAR. TCHARnem mesmo está na biblioteca padrão, então não, a std::tcoutmenos que você mesmo queira definir.

O que eu recomendo em vez de TCHAR

Esqueça que existem codificações "ANSI", exceto quando você precisar ler um arquivo que não é UTF-8 válido. Esqueça TCHARtambém. Sempre chame a versão "W" das funções da API do Windows. #define _UNICODEapenas para ter certeza de não chamar acidentalmente uma função "A".

Sempre use codificações UTF para strings: UTF-8 para charstrings e UTF-16 (no Windows) ou UTF-32 (em sistemas do tipo Unix) para wchar_tstrings. typedef UTF16e UTF32tipos de personagens para evitar diferenças de plataforma.

dan04
fonte
6
Chamada de 2012: ainda há aplicativos a serem mantidos, #define _UNICODEmesmo agora. Fim da transmissão :)
0xC0000022L
12
@ 0xC0000022L a pergunta era sobre o novo código. Quando você mantém um código antigo, obviamente precisa trabalhar com o ambiente para o qual o código foi escrito. Se você está mantendo um aplicativo COBOL, não importa se COBOL é uma boa linguagem ou não, você está preso a ela. E se você está mantendo um aplicativo que depende do TCHAR, não importa se essa foi uma boa decisão ou não, você está preso a ela.
jalf
2
Na verdade, TCHAR não é útil, a menos que em COBOL)
Pavel Radzivilovsky
1
_UNICODEcontrola como os mapeamentos de texto genérico são resolvidos no CRT. Se você não deseja chamar a versão ANSI de uma API do Windows, você precisa definir UNICODE.
Inspecionável
18

Se você está se perguntando se ainda está em prática, então sim - ainda é bastante usado. Ninguém vai achar engraçado seu código se ele usar TCHAR e _T (""). O projeto no qual estou trabalhando agora é a conversão de ANSI para Unicode - e estamos seguindo a rota portátil (TCHAR).

Contudo...

Meu voto seria esquecer todas as macros portáteis ANSI / UNICODE (TCHAR, _T (""), e todas as chamadas _tXXXXXX, etc ...) e apenas assumir unicode em todos os lugares. Realmente não vejo sentido em ser portátil se você nunca precisará de uma versão ANSI. Eu usaria todas as funções e tipos de caracteres amplos diretamente. Preprender todos os literais de string com um L.

Aardvark
fonte
3
Você pode escrever algum código que deseja usar em outro lugar onde você precisa de uma versão ANSI, ou (como Nick disse) o Windows pode mover para DCHAR ou qualquer outro, então eu ainda acho que é uma boa ideia ir com TCHAR em vez de WCHAR.
arke
Duvido que o Windows vá mudar para UTF-32.
dan04,
7
-1 para recomendação UTF-16. Não apenas isso cria um código não portátil (centrado no Windows), o que é inaceitável para bibliotecas - embora possa ser usado para os casos mais simples, como o código da IU - não é eficiente nem mesmo no próprio Windows. utf8everywhere.org
Pavel Radzivilovsky
11

O artigo de introdução à programação do Windows no MSDN diz

Novos aplicativos devem sempre chamar as versões Unicode (da API).

As macros TEXT e TCHAR são menos úteis hoje, porque todos os aplicativos devem usar Unicode.

Eu ficaria com wchar_te L"".

Steven
fonte
4
Steven, você está citando um texto escrito por alguém que não entende o significado da palavra 'Unicode'. É um daqueles documentos infelizes da época da confusão UCS-2.
Pavel Radzivilovsky
2
@PavelRadzivilovsky: o documento foi escrito para um sistema, onde Unicode e UTF-16LE são comumente usados ​​alternadamente. Embora tecnicamente impreciso, não deixa de ser ambíguo. Isso também é explicitamente indicado na introdução do mesmo texto: "O Windows representa caracteres Unicode usando a codificação UTF-16 [...]" .
Inspecionável
11

Eu gostaria de sugerir uma abordagem diferente (nenhuma das duas).

Para resumir, use char * e std :: string, assumindo a codificação UTF-8, e faça as conversões para UTF-16 apenas ao agrupar funções API.

Mais informações e justificativas para essa abordagem em programas do Windows podem ser encontradas em http://www.utf8everywhere.org .

Pavel Radzivilovsky
fonte
@PavelRadzivilovsky, ao implementar sua sugestão em um aplicativo VC ++, definiríamos o caractere VC ++ definido como 'Nenhum' ou 'Multibyte (MBCS)'? Estou perguntando porque acabei de instalar o Boost :: Locale e o conjunto de caracteres padrão era MBCS. FWIW, meu aplicativo ASCII puro foi definido como 'Nenhum' e agora o defini como 'MBCS' (já que estarei usando Boost :: Locale nele) e funciona perfeitamente. Por favor informar.
Caroline Beltran
Conforme recomendado pelo utf8everywhere, eu definiria como 'Usar conjunto de caracteres Unicode'. Isso anuncia segurança extra, mas não é obrigatório. O autor de Boost :: locale é um cara muito inteligente, mas tenho certeza que ele fez a coisa certa.
Pavel Radzivilovsky
1
O mantra UTF-8 Everywhere não se tornará a solução certa, apenas porque é repetido com mais frequência. UTF-8 é, sem dúvida, uma codificação atraente para serialização (por exemplo, arquivos ou soquetes de rede), mas no Windows é freqüentemente mais apropriado armazenar dados de caracteres usando a codificação UTF-16 nativa internamente e converter no limite do aplicativo. Um dos motivos é que UTF-16 é a única codificação que pode ser convertida imediatamente em qualquer outra codificação compatível. Este não é o caso do UTF-8.
Inspecionável
"..UTF-16 é a única codificação, que pode ser convertida imediatamente para qualquer outra codificação compatível." O que você quer dizer? Qual é o problema para converter a codificação UTF-8 para qualquer outra coisa?
Pavel Radzivilovsky
1
Eu não entendi. Para qualquer outra coisa - como o quê? Por exemplo, UCS-4? Por que não? Parece muito fácil, todo algoritmo numérico ..
Pavel Radzivilovsky
7

TCHAR/ WCHARpode ser suficiente para alguns projetos legados. Mas para novos aplicativos, eu diria NÃO .

Todas essas TCHAR/ WCHARcoisas estão lá por razões históricas. TCHARfornece uma maneira simples (disfarce) de alternar entre a codificação de texto ANSI (MBCS) e a codificação de texto Unicode (UTF-16). No passado, as pessoas não entendiam o número de caracteres de todas as línguas do mundo. Eles assumiram que 2 bytes eram suficientes para representar todos os caracteres e, portanto, usando um esquema de codificação de caracteres de comprimento fixo WCHAR. No entanto, isso não é mais verdade após o lançamento do Unicode 2.0 em 1996 .

Quer dizer: Não importa o que você use em CHAR/ WCHAR/ TCHAR, a parte de processamento de texto em seu programa deve ser capaz de lidar com caracteres de comprimento variável para internacionalização.

Então, você realmente precisa fazer mais do que escolher um de CHAR/ WCHAR/ TCHARpara programar no Windows:

  1. Se seu aplicativo for pequeno e não envolver processamento de texto (ou seja, apenas passar a string de texto como argumentos), continue WCHAR. Uma vez que desta forma é mais fácil trabalhar com WinAPI com suporte a Unicode.
  2. Caso contrário, eu sugeriria usar UTF-8 como codificação interna e armazenar textos em strings char ou std :: string. E converta-os para UTF-16 ao chamar WinAPI. UTF-8 agora é a codificação dominante e há muitas bibliotecas e ferramentas úteis para processar strings UTF-8.

Confira este maravilhoso site para uma leitura mais aprofundada: http://utf8everywhere.org/

Leopardo
fonte
2
"UTF-8 agora é a codificação dominante" - Isso deu errado, deixando de fora a segunda parte da citação ( "para a World Wide Web" ). Para aplicativos de desktop, a codificação de caracteres nativos mais usada provavelmente ainda é UTF-16. O Windows usa, o Mac OS X também, e também os tipos de string do .NET e do Java. Isso é responsável por uma grande quantidade de código por aí. Não me entenda mal, não há nada de errado com UTF-8 para serialização. Porém, na maioria das vezes (especialmente no Windows), você descobrirá que usar UTF-16 internamente é mais apropriado.
Inspecionável
4

Sim absolutamente; pelo menos para a macro _T. Eu não tenho tanta certeza sobre as coisas de caráter amplo, no entanto.

A razão é para melhor oferecer suporte ao WinCE ou outras plataformas Windows não padrão. Se você tiver 100% de certeza de que seu código permanecerá no NT, provavelmente poderá usar apenas as declarações normais de strings C. No entanto, é melhor tender para a abordagem mais flexível, pois é muito mais fácil #define essa macro em uma plataforma não Windows em comparação a passar por milhares de linhas de código e adicioná-la em qualquer lugar, caso você precise portar alguma biblioteca para o Windows Mobile.

Nik Reiman
fonte
1
O WinCE usa strings wchar_t de 16 bits, assim como o Win32. Temos uma grande base de código que roda em WinCE e Win32 e nunca usamos TCHAR.
mhenry1384
2

IMHO, se houver TCHARs em seu código, você está trabalhando no nível errado de abstração.

Use o tipo de string que for mais conveniente para você ao lidar com processamento de texto - espero que seja algo que suporte Unicode, mas isso é com você. Faça a conversão nos limites da API do sistema operacional conforme necessário.

Ao lidar com caminhos de arquivo, crie seu próprio tipo personalizado em vez de usar strings. Isso permitirá separadores de caminho independentes do sistema operacional, proporcionará uma interface mais fácil de codificar do que concatenação e divisão manual de strings e será muito mais fácil de se adaptar a diferentes sistemas operacionais (ansi, ucs-2, utf-8, qualquer que seja) .

snemarch
fonte
O Unicode tem pelo menos três codificações atuais (UTF-8, UTF-16, UTF-32) e uma codificação obsoleta (UCS-2, um subconjunto do que agora é UTF-16). A qual você se refere? Eu gosto do resto das sugestões, embora +1
0xC0000022L
2

As únicas razões que vejo para usar algo diferente do WCHAR explícito são portabilidade e eficiência.

Se você quiser tornar seu executável final o menor possível, use char.

Se você não se importa com o uso de RAM e deseja que a internacionalização seja tão fácil quanto uma simples tradução, use o WCHAR.

Se você quiser tornar seu código flexível, use TCHAR.

Se você planeja usar apenas os caracteres latinos, também pode usar as strings ASCII / MBCS para que o usuário não precise de tanta RAM.

Para pessoas que são "i18n desde o início", economize o espaço do código-fonte e simplesmente use todas as funções Unicode.

Trololol
fonte
-1

Apenas adicionando a uma velha questão:

NÃO

Vá iniciar um novo projeto CLR C ++ no VS2010. A própria Microsoft usa L"Hello World", 'disse Nuff.

kizzx2
fonte
13
O CLR é um ambiente muito diferente do código não gerenciado. Isso não é um argumento.
Cody Gray
3
Até a Microsoft comete erros.
Pavel Radzivilovsky
6
-1 A questão está marcada Ce C++. As respostas sempre podem ser excluídas por seus respectivos autores. Este seria um bom momento para usar essa provisão.
Inspecionável
-1

TCHARtêm um novo significado para transferir de WCHARpara CHAR.

https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page

Versões recentes do Windows 10 usaram a página de código ANSI e APIs -A como um meio de apresentar o suporte UTF-8 aos aplicativos. Se a página de código ANSI estiver configurada para UTF-8, as APIs -A operam em UTF-8.

OwnageIsMagic
fonte