TCHAR è ancora rilevante?


87

Sono nuovo nella programmazione Windows e dopo aver letto il libro di Petzold mi chiedo:

è ancora una buona pratica usare il TCHARtipo e la _T()funzione per dichiarare le stringhe o se dovrei usare solo le stringhe wchar_te L""nel nuovo codice?

Mirerò solo a Windows 2000 e versioni successive e il mio codice sarà i18n dall'inizio.

Risposte:


15

Userei ancora la sintassi TCHAR se stavo facendo un nuovo progetto oggi. Non c'è molta differenza pratica tra usarlo e la sintassi WCHAR, e preferisco il codice che è esplicito nel tipo di carattere. Poiché la maggior parte delle funzioni API e degli oggetti helper accettano / utilizzano i tipi TCHAR (ad esempio: CString), ha senso usarlo. Inoltre ti dà flessibilità se ad un certo punto decidi di utilizzare il codice in un'app ASCII o se Windows si evolve in Unicode32, ecc.

Se decidi di seguire il percorso WCHAR, sarei esplicito al riguardo. Vale a dire, utilizzare CStringW invece di CString e eseguire il cast delle macro durante la conversione in TCHAR (ad esempio: CW2CT).

Questa è la mia opinione, comunque.


In effetti, è quello che funzionerà ancora quando la codifica dei caratteri verrà eventualmente modificata "di nuovo".
Medinoc

11
Preferisci il codice che è esplicito in quello che è il tipo di carattere, e quindi usi un tipo che a volte è questo e talvolta quello? Molto persuasivo.
Deduplicator

4
-1 per l'incoerenza rilevata da @Deduplicator e per il consiglio di payoff negativo di utilizzare una macro che può essere qualunque (e generalmente non verrà testata per più di un valore specifico).
Saluti e salute. - Alf

90

La risposta breve: NO .

Come tutti gli altri già scritti, molti programmatori usano ancora i TCHAR e le funzioni corrispondenti. A mio modesto parere, l'intero concetto era una cattiva idea . L' elaborazione delle stringhe UTF-16 è molto diversa dalla semplice elaborazione delle stringhe ASCII / MBCS. Se usi gli stessi algoritmi / funzioni con entrambi (questo è ciò su cui si basa l'idea TCHAR!), Ottieni prestazioni pessime sulla versione UTF-16 se stai facendo qualcosa di più della semplice concatenazione di stringhe (come analisi ecc.). Il motivo principale sono i surrogati .

Con la sola eccezione quando devi davvero compilare la tua applicazione per un sistema che non supporta Unicode, non vedo alcun motivo per utilizzare questo bagaglio del passato in una nuova applicazione.


6
Curiosità: UTF-16 non era sempre presente sulla piattaforma NT. I punti di codice surrogati sono stati introdotti con Unicode 2.0, nel 1996, lo stesso anno in cui è stato rilasciato NT 4. Fino a IIRC, (incluso) Windows 2000 tutte le versioni di NT utilizzavano UCS-2, effettivamente un sottoinsieme di UTF-16 che assumeva che ogni carattere fosse rappresentabile con un punto di codice (cioè senza surrogati).
0xC0000022L

3
btw, mentre sono d'accordo che TCHARnon dovrebbe essere usato più, non sono d'accordo che questa sia stata una cattiva idea. Penso anche che se scegli di essere esplicito invece di usare TCHARdovresti essere esplicito ovunque . Vale a dire non usare neanche funzioni con TCHAR/ _TCHAR(come _tmain) nella loro dichiarazione. In poche parole: sii coerente. +1, ancora.
0xC0000022L

3
Era una buona idea quando è stato introdotto, ma dovrebbe essere irrilevante nel nuovo codice.
Adrian McCarthy

4
Travisate ciò TCHARper cui sono stati inizialmente introdotti: Per facilitare lo sviluppo di codice per le versioni di Windows basate su Windows 9x e Windows NT. A quel tempo, l'implementazione UTF-16 di Windows NT era UCS-2 e gli algoritmi per l'analisi / manipolazione delle stringhe erano identici. Non c'erano surrogati. E anche con i surrogati, gli algoritmi per DBCS (l'unica codifica MBCS supportata per Windows) e UTF-16 sono gli stessi: in entrambe le codifiche, un punto di codice è costituito da una o due unità di codice.
Rilevabile

Supponiamo di voler utilizzare FormatMessage () per convertire un valore da WSAGetLastError () a qualcosa di stampabile. La documentazione per WSAGetLastError () dice che accetta LPTSTR come puntatore al buffer. Non ho molta scelta se non quella di usare TCHAR, no?
Edward Falk

80

Sono d'accordo con Sascha. La premessa alla base di TCHAR/ _T()/ ecc. È che puoi scrivere un'applicazione basata su "ANSI" e quindi fornirle magicamente il supporto Unicode definendo una macro. Ma questo si basa su diversi presupposti sbagliati:

Che crei attivamente entrambe le versioni MBCS e Unicode del tuo software

In caso contrario, sarà scivolare e utilizzare normali char*stringhe in molti luoghi.

Che non usi caratteri di escape con barra rovesciata non ASCII nei letterali _T ("...")

A meno che la codifica "ANSI" non sia ISO-8859-1, i valori letterali char*e risultanti wchar_t*non rappresenteranno gli stessi caratteri.

Quelle stringhe UTF-16 vengono utilizzate proprio come le stringhe "ANSI"

Loro non sono. Unicode introduce diversi concetti che non esistono nella maggior parte delle codifiche di caratteri legacy. Surrogati. Combinare i personaggi. Normalizzazione. Regole di maiuscole / minuscole condizionali e dipendenti dalla lingua.

E forse la cosa più importante, il fatto che UTF-16 viene raramente salvato su disco o inviato su Internet: UTF-8 tende ad essere preferito per la rappresentazione esterna.

Che la tua applicazione non utilizza Internet

(Ora, questo potrebbe essere un presupposto valido per il tuo software, ma ...)

Il web gira su UTF-8 e una pletora di codifiche più rare . Il TCHARconcetto ne riconosce solo due: "ANSI" (che non può essere UTF-8 ) e "Unicode" (UTF-16). Può essere utile per rendere le tue chiamate API Windows compatibili con Unicode, ma è dannatamente inutile per rendere le tue app Web e di posta elettronica compatibili con Unicode.

Che non usi librerie non Microsoft

Nessun altro usa TCHAR. Poco utilizza std::stringe UTF-8. SQLite ha le versioni UTF-8 e UTF-16 della sua API, ma no TCHAR. TCHARnon è nemmeno nella libreria standard, quindi no a std::tcoutmeno che tu non voglia definirlo tu stesso.

Quello che raccomando invece di TCHAR

Dimentica che esistono le codifiche "ANSI", tranne quando devi leggere un file che non è valido UTF-8. Dimentica TCHARanche tu . Chiama sempre la versione "W" delle funzioni API di Windows. #define _UNICODEsolo per assicurarti di non chiamare accidentalmente una funzione "A".

Usa sempre le codifiche UTF per le stringhe: UTF-8 per le charstringhe e UTF-16 (su Windows) o UTF-32 (su sistemi Unix-like) per le wchar_tstringhe. typedef UTF16e UTF32tipi di carattere per evitare differenze di piattaforma.


6
Call 2012: ci sono ancora applicazioni da mantenere senza #define _UNICODEanche adesso. Fine della trasmissione :)
0xC0000022L

12
@ 0xC0000022L la domanda riguardava il nuovo codice. Quando mantieni il vecchio codice, devi ovviamente lavorare con l'ambiente per cui il codice è stato scritto. Se stai gestendo un'applicazione COBOL, non importa se COBOL è un buon linguaggio o meno, sei bloccato con esso. E se stai mantenendo un'applicazione che si basa su TCHAR, non importa se è stata una buona decisione o meno, sei bloccato con esso.
jalf

2
In effetti, TCHAR non è utile se non in COBOL)
Pavel Radzivilovsky

1
_UNICODEcontrolla come vengono risolte le mappature del testo generico nel CRT. Se non vuoi chiamare la versione ANSI di un'API di Windows, devi definire UNICODE.
Rilevabile il

18

Se ti stai chiedendo se è ancora in pratica, allora sì, è ancora usato un bel po '. Nessuno guarderà il tuo codice in modo divertente se usa TCHAR e _T (""). Il progetto su cui sto lavorando ora sta convertendo da ANSI a unicode - e stiamo seguendo il percorso portatile (TCHAR).

Però...

Il mio voto sarebbe quello di dimenticare tutte le macro portatili ANSI / UNICODE (TCHAR, _T ("") e tutte le chiamate _tXXXXXX, ecc ...) e assumere l'unicode ovunque. Non vedo davvero il punto di essere portatile se non avrai mai bisogno di una versione ANSI. Userei direttamente tutte le funzioni ei tipi di caratteri wide. Preprend tutte le stringhe letterali con una L.


3
Potresti scrivere del codice che vorresti usare da qualche altra parte dove hai bisogno di una versione ANSI, o (come ha detto Nick) Windows potrebbe passare a DCHAR o qualsiasi altra cosa, quindi penso ancora che sia un'ottima idea andare con TCHAR invece di WCHAR.
arke

Dubito che Windows passerà mai a UTF-32.
dan04

7
-1 per la raccomandazione UTF-16. Non solo questo crea codice non portabile (incentrato su Windows), che è inaccettabile per le librerie - anche se può essere usato per i casi più semplici come il codice dell'interfaccia utente - non è efficiente nemmeno su Windows stesso. utf8everywhere.org
Pavel Radzivilovsky

11

L'articolo Introduzione alla programmazione Windows su MSDN dice

Le nuove applicazioni dovrebbero sempre chiamare le versioni Unicode (dell'API).

Le macro TEXT e TCHAR sono oggi meno utili, perché tutte le applicazioni dovrebbero usare Unicode.

Mi atterrei a wchar_te L"".


4
Steven, stai citando un testo scritto da qualcuno che non capisce il significato della parola "Unicode". È uno di quegli sfortunati documenti dell'epoca della confusione UCS-2.
Pavel Radzivilovsky

2
@PavelRadzivilovsky: Il documento è stato scritto per un sistema, dove Unicode e UTF-16LE sono comunemente usati in modo intercambiabile. Sebbene tecnicamente impreciso, è comunque inequivocabile. Questo è anche esplicitamente sottolineato nell'introduzione dello stesso testo: "Windows rappresenta i caratteri Unicode usando la codifica UTF-16 [...]" .
Rilevabile il

11

Vorrei suggerire un approccio diverso (nessuno dei due).

Per riassumere, usa char * e std :: string, assumendo la codifica UTF-8, ed esegui le conversioni in UTF-16 solo quando avvolgi le funzioni API.

Maggiori informazioni e giustificazioni per questo approccio nei programmi Windows possono essere trovate in http://www.utf8everywhere.org .


@PavelRadzivilovsky, quando implementiamo il tuo suggerimento in un'applicazione VC ++, dovremmo impostare il carattere VC ++ impostato su "Nessuno" o "Multibyte (MBCS)"? Il motivo per cui lo chiedo è che ho appena installato Boost :: Locale e il set di caratteri predefinito era MBCS. FWIW, la mia applicazione ASCII pura era impostata su "Nessuno" e ora l'ho impostata su "MBCS" (poiché utilizzerò Boost :: Locale) e funziona perfettamente. Si prega di avvisare.
Caroline Beltran,

Come consiglia utf8everywhere, lo impostare su "Usa set di caratteri Unicode". Questo annuncio maggiore sicurezza, ma non è obbligatorio. L'autore di Boost :: locale è un ragazzo molto intelligente, sono sicuro che abbia fatto la cosa giusta.
Pavel Radzivilovsky,

1
Il mantra UTF-8 Everywhere non diventerà la soluzione giusta, solo perché viene ripetuto più spesso. UTF-8 è indubbiamente una codifica attraente per la serializzazione (ad esempio file o socket di rete), ma su Windows è spesso più appropriato memorizzare i dati dei caratteri utilizzando la codifica UTF-16 nativa internamente e convertirli al confine dell'applicazione. Uno dei motivi è che UTF-16 è l'unica codifica che può essere convertita immediatamente in qualsiasi altra codifica supportata. Questo non è il caso di UTF-8.
Rilevabile

"..UTF-16 è l'unica codifica che può essere convertita immediatamente in qualsiasi altra codifica supportata." cosa intendi? Qual è il problema nel convertire la codifica UTF-8 in qualcos'altro?
Pavel Radzivilovsky

1
Non capisco. A qualsiasi altra cosa - come cosa? Ad esempio UCS-4? Perchè no? Sembra molto facile, tutto l'algoritmo numerico ..
Pavel Radzivilovsky

7

TCHAR/ WCHARpotrebbe essere sufficiente per alcuni progetti legacy. Ma per nuove applicazioni, direi NO .

Tutte queste TCHAR/ WCHARcose sono lì per ragioni storiche. TCHARfornisce un modo apparentemente pulito (travestimento) per passare dalla codifica del testo ANSI (MBCS) alla codifica del testo Unicode (UTF-16). In passato, le persone non avevano una comprensione del numero di caratteri di tutte le lingue del mondo. Presumevano che 2 byte fossero sufficienti per rappresentare tutti i caratteri e quindi utilizzando uno schema di codifica dei caratteri a lunghezza fissa WCHAR. Tuttavia, questo non è più vero dopo il rilascio di Unicode 2.0 nel 1996 .

Vale a dire: indipendentemente da quale si utilizza in CHAR/ WCHAR/ TCHAR, la parte di elaborazione del testo nel programma dovrebbe essere in grado di gestire caratteri di lunghezza variabile per l'internazionalizzazione.

Quindi in realtà devi fare di più che sceglierne uno da CHAR/ WCHAR/ TCHARper la programmazione in Windows:

  1. Se la tua applicazione è piccola e non coinvolge l'elaborazione del testo (cioè solo il passaggio della stringa di testo come argomenti), continua con WCHAR. Poiché in questo modo è più semplice lavorare con WinAPI con supporto Unicode.
  2. Altrimenti, suggerirei di utilizzare UTF-8 come codifica interna e memorizzare i testi in stringhe di caratteri o std :: string. E convertili in UTF-16 quando chiami WinAPI. UTF-8 è ora la codifica dominante e ci sono molte librerie e strumenti utili per elaborare le stringhe UTF-8.

Dai un'occhiata a questo meraviglioso sito web per una lettura più approfondita: http://utf8everywhere.org/


2
"UTF-8 è ora la codifica dominante" - Questo è risultato sbagliato, tralasciando la seconda parte della citazione ( "per il World Wide Web" ). Per le applicazioni desktop, la codifica dei caratteri nativa più utilizzata è probabilmente ancora UTF-16. Windows lo usa, anche Mac OS X, e così anche i tipi di stringa di .NET e Java. Ciò spiega una quantità enorme di codice là fuori. Non fraintendetemi, non c'è niente di sbagliato in UTF-8 per la serializzazione. Ma il più delle volte (specialmente su Windows), scoprirai che usare UTF-16 internamente è più appropriato.
Rilevabile

4

Si assolutamente; almeno per la macro _T. Non sono così sicuro delle cose del carattere ampio, però.

Il motivo è supportare meglio WinCE o altre piattaforme Windows non standard. Se sei sicuro al 100% che il tuo codice rimarrà su NT, allora probabilmente puoi semplicemente usare le normali dichiarazioni di stringa C. Tuttavia, è meglio tendere verso un approccio più flessibile, poiché è molto più facile #definire quella macro su una piattaforma non Windows rispetto a passare attraverso migliaia di righe di codice e aggiungerla ovunque nel caso sia necessario eseguire il port di alcune librerie a Windows Mobile.


1
WinCE utilizza stringhe wchar_t a 16 bit proprio come Win32. Abbiamo un'ampia base di codice che gira su WinCE e Win32 e non usiamo mai TCHAR.
mhenry1384

2

IMHO, se ci sono TCHAR nel tuo codice, stai lavorando al livello di astrazione sbagliato.

Utilizzare qualunque tipo di stringa è più conveniente per voi quando si tratta di elaborazione del testo - questo si spera qualcosa unicode di sostegno, ma che sta a voi. Eseguire la conversione ai limiti dell'API del sistema operativo, se necessario.

Quando hai a che fare con i percorsi dei file, crea il tuo tipo personalizzato invece di usare le stringhe. Questo ti consentirà separatori di percorso indipendenti dal sistema operativo, ti darà un'interfaccia più semplice da codificare rispetto alla concatenazione e alla suddivisione manuale di stringhe e sarà molto più facile adattarsi a diversi sistemi operativi (ansi, ucs-2, utf-8, qualunque cosa) .


Unicode ha almeno tre codifiche correnti (UTF-8, UTF-16, UTF-32) e una codifica obsoleta (UCS-2, un sottoinsieme di quello che ora è UTF-16). A quale ti riferisci? Mi piace il resto dei suggerimenti anche se +1
0xC0000022L

2

Le uniche ragioni che vedo per usare qualcosa di diverso dall'esplicito WCHAR sono la portabilità e l'efficienza.

Se vuoi rendere il tuo eseguibile finale il più piccolo possibile usa char.

Se non ti interessa l'utilizzo della RAM e desideri che l'internazionalizzazione sia facile come una semplice traduzione, usa WCHAR.

Se vuoi rendere flessibile il tuo codice, usa TCHAR.

Se prevedi di utilizzare solo i caratteri latini, potresti anche utilizzare le stringhe ASCII / MBCS in modo che l'utente non abbia bisogno di molta RAM.

Per le persone che sono "i18n dall'inizio", risparmia lo spazio del codice sorgente e usa semplicemente tutte le funzioni Unicode.


-1

Aggiungo solo a una vecchia domanda:

NO

Inizia un nuovo progetto CLR C ++ in VS2010. Microsoft stessa usa L"Hello World", 'nuff ha detto.


13
CLR è un ambiente molto diverso dal codice non gestito. Cioè non è un argomento.
Cody Grey

3
Anche Microsoft commette errori.
Pavel Radzivilovsky

6
-1 La domanda è contrassegnata Ce C++. Le risposte possono sempre essere eliminate dai rispettivi autori. Questo sarebbe un buon momento per utilizzare tale disposizione.
Rilevabile il

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.