Ist TCHAR noch relevant?

87

Ich bin neu in der Windows-Programmierung und nachdem ich das Petzold-Buch gelesen habe, frage ich mich:

Ist es immer noch eine gute Praxis, den TCHARTyp und die _T()Funktion zum Deklarieren von Zeichenfolgen zu verwenden, oder sollte ich nur die Zeichenfolgen wchar_tund L""in neuem Code verwenden?

Ich werde nur auf Windows 2000 und höher abzielen und mein Code wird von Anfang an i18n sein.

Fábio
quelle

Antworten:

15

Ich würde immer noch die TCHAR-Syntax verwenden, wenn ich heute ein neues Projekt machen würde. Es gibt keinen großen praktischen Unterschied zwischen der Verwendung und der WCHAR-Syntax, und ich bevorzuge Code, der im Zeichentyp explizit angegeben ist. Da die meisten API-Funktionen und Hilfsobjekte TCHAR-Typen (z. B. CString) verwenden, ist es nur sinnvoll, sie zu verwenden. Außerdem erhalten Sie Flexibilität, wenn Sie sich entscheiden, den Code irgendwann in einer ASCII-App zu verwenden, oder wenn Windows jemals zu Unicode32 usw. weiterentwickelt wird.

Wenn Sie sich für die WCHAR-Route entscheiden, würde ich dies ausdrücklich erwähnen. Verwenden Sie also CStringW anstelle von CString und setzen Sie beim Konvertieren in TCHAR Makros um (z. B. CW2CT).

Das ist jedenfalls meine Meinung.

Nick
quelle
In der Tat wird dies immer noch funktionieren, wenn die Zeichenkodierung irgendwann wieder geändert wird.
Medinoc
11
Sie bevorzugen Code, der explizit in dem Zeichentyp enthalten ist, und verwenden daher einen Typ, der manchmal dies und manchmal das ist? Sehr überzeugend.
Deduplikator
4
−1 für die von @Deduplicator festgestellte Inkonsistenz und für die negative Auszahlungsempfehlung, ein Makro zu verwenden, das beliebig sein kann (und im Allgemeinen nicht auf mehr als einen bestimmten Wert getestet wird).
Prost und hth. - Alf
90

Die kurze Antwort: NEIN .

Wie alle anderen bereits geschrieben haben, verwenden viele Programmierer immer noch TCHARs und die entsprechenden Funktionen. Meiner bescheidenen Meinung nach war das ganze Konzept eine schlechte Idee . Die UTF-16- Zeichenfolgenverarbeitung unterscheidet sich stark von der einfachen ASCII / MBCS-Zeichenfolgenverarbeitung. Wenn Sie mit beiden dieselben Algorithmen / Funktionen verwenden (darauf basiert die TCHAR-Idee!), Erhalten Sie in der UTF-16-Version eine sehr schlechte Leistung, wenn Sie ein wenig mehr als nur eine einfache Zeichenfolgenverkettung ausführen (z Parsen etc.). Der Hauptgrund sind Surrogate .

Mit der einzigen Ausnahme, wenn Sie Ihre Anwendung wirklich für ein System kompilieren müssen, das Unicode nicht unterstützt, sehe ich keinen Grund, dieses Gepäck aus der Vergangenheit in einer neuen Anwendung zu verwenden.

Sascha
quelle
6
Unterhaltsame Tatsache: UTF-16 war auf der NT-Plattform nicht immer vorhanden. Ersatzcodepunkte wurden 1996 mit Unicode 2.0 eingeführt, im selben Jahr, in dem NT 4 veröffentlicht wurde. Bis IIRC (einschließlich) Windows 2000 verwendeten alle NT-Versionen UCS-2, effektiv eine Teilmenge von UTF-16, bei der angenommen wurde, dass jedes Zeichen mit einem Codepunkt darstellbar ist (dh keine Ersatzzeichen).
0xC0000022L
3
Übrigens stimme ich zu, dass dies TCHARnicht mehr verwendet werden sollte, aber ich bin nicht der Meinung, dass dies eine schlechte Idee war. Ich denke auch, dass Sie überall explizit sein sollten , wenn Sie sich dafür entscheiden, explizit zu sein, anstatt zu verwenden . Dh auch keine Funktionen mit / (wie ) in ihrer Deklaration verwenden. Einfach ausgedrückt: Seien Sie konsequent. +1, immer noch. TCHARTCHAR_TCHAR_tmain
0xC0000022L
3
Es war eine gute Idee, als es eingeführt wurde, aber es sollte in neuem Code irrelevant sein.
Adrian McCarthy
4
Sie stellen falsch dar, wofür TCHARursprünglich eingeführt wurde: Um die Entwicklung von Code für Windows 9x- und Windows NT-basierte Windows-Versionen zu vereinfachen. Zu dieser Zeit war die UTF-16-Implementierung von Windows NT UCS-2, und die Algorithmen für das Parsen / Manipulieren von Zeichenfolgen waren identisch. Es gab keine Leihmütter. Und selbst bei Ersatzzeichen sind die Algorithmen für DBCS (die einzige unterstützte MBCS-Codierung für Windows) und UTF-16 identisch: Bei beiden Codierungen besteht ein Codepunkt aus einer oder zwei Codeeinheiten.
Unsichtbarer
Angenommen, ich möchte FormatMessage () verwenden, um einen Wert von WSAGetLastError () in etwas Druckbares zu konvertieren. In der Dokumentation zu WSAGetLastError () heißt es, dass LPTSTR als Zeiger auf den Puffer verwendet wird. Ich habe wirklich keine andere Wahl, als TCHAR zu verwenden, nein?
Edward Falk
80

Ich muss Sascha zustimmen. Die zugrunde liegende Prämisse von TCHAR/_T() / etc. ist, dass Sie eine "ANSI" -basierte Anwendung schreiben und ihr dann auf magische Weise Unicode-Unterstützung geben können, indem Sie ein Makro definieren. Dies basiert jedoch auf mehreren schlechten Annahmen:

Dass Sie aktiv sowohl MBCS- als auch Unicode-Versionen Ihrer Software erstellen

Andernfalls Sie wird nach oben rutschen und verwenden gewöhnlichechar* Strings in vielen Orten.

Dass Sie keinen Nicht-ASCII-Backslash verwenden, wird in _T ("...") - Literalen maskiert

Sofern Ihre "ANSI" -Codierung nicht ISO-8859-1 ist, repräsentieren das Ergebnis char*und die wchar_t*Literale nicht dieselben Zeichen.

Diese UTF-16-Zeichenfolgen werden genau wie "ANSI" -Strings verwendet

Sie sind nicht. Unicode führt verschiedene Konzepte ein, die in den meisten älteren Zeichenkodierungen nicht vorhanden sind. Surrogate. Charaktere kombinieren. Normalisierung. Bedingte und sprachempfindliche Gehäuseregeln.

Und vielleicht am wichtigsten ist die Tatsache, dass UTF-16 selten auf der Festplatte gespeichert oder über das Internet gesendet wird: UTF-8 wird für die externe Darstellung bevorzugt.

Dass Ihre Anwendung das Internet nicht nutzt

(Nun, dies kann eine gültige Annahme für Ihre Software sein, aber ...)

Das Web läuft auf UTF-8 und einer Vielzahl seltener Codierungen . Das TCHARKonzept erkennt nur zwei: "ANSI" (das kann nicht UTF-8 sein ) und "Unicode" (UTF-16). Es kann nützlich sein, um Ihre Windows-API-Aufrufe Unicode-fähig zu machen, aber es ist verdammt nutzlos, um Ihre Web- und E-Mail-Apps Unicode-fähig zu machen.

Dass Sie keine Nicht-Microsoft-Bibliotheken verwenden

Niemand sonst benutzt TCHAR. Poco verwendet std::stringund UTF-8. SQLite hat UTF-8- und UTF-16-Versionen seiner API, aber nein TCHAR. TCHARist nicht einmal in der Standardbibliothek, also neinstd::tcout sei denn, Sie möchten es selbst definieren.

Was ich anstelle von TCHAR empfehle

Vergessen Sie, dass "ANSI" -Codierungen vorhanden sind, außer wenn Sie eine Datei lesen müssen, die nicht für UTF-8 gültig ist. Vergiss es TCHARauch. Rufen Sie immer die "W" -Version der Windows-API-Funktionen auf. #define _UNICODENur um sicherzustellen, dass Sie nicht versehentlich eine "A" -Funktion aufrufen.

Verwenden Sie immer UTF-Codierungen für Zeichenfolgen: UTF-8 für charZeichenfolgen und UTF-16 (unter Windows) oder UTF-32 (auf Unix-ähnlichen Systemen) für wchar_tZeichenfolgen. typedef UTF16und UTF32Zeichentypen, um Plattformunterschiede zu vermeiden.

dan04
quelle
6
2012 Aufruf: Es gibt noch Anwendungen, ohne die #define _UNICODEauch jetzt noch gewartet werden muss . Ende der Übertragung :)
0xC0000022L
12
@ 0xC0000022L Die Frage betraf neuen Code. Wenn Sie alten Code pflegen, müssen Sie natürlich mit der Umgebung arbeiten , für die der Code geschrieben wurde. Wenn Sie eine COBOL-Anwendung pflegen, spielt es keine Rolle, ob COBOL eine gute Sprache ist oder nicht, Sie bleiben dabei. Und wenn Sie eine Anwendung pflegen, die auf TCHAR basiert, spielt es keine Rolle, ob dies eine gute Entscheidung war oder nicht, Sie bleiben dabei.
Jalf
2
In der Tat ist TCHAR nur in COBOL) nützlich
Pavel Radzivilovsky
1
_UNICODESteuert, wie die generischen Textzuordnungen in der CRT aufgelöst werden. Wenn Sie die ANSI-Version einer Windows-API nicht aufrufen möchten, müssen Sie definieren UNICODE.
IInspectable
18

Wenn Sie sich fragen, ob es noch in der Praxis ist, dann ja - es wird immer noch ziemlich oft verwendet. Niemand wird Ihren Code lustig ansehen, wenn er TCHAR und _T ("") verwendet. Das Projekt, an dem ich gerade arbeite, konvertiert von ANSI zu Unicode - und wir gehen den tragbaren Weg (TCHAR).

Jedoch...

Meine Stimme wäre, alle tragbaren ANSI / UNICODE-Makros (TCHAR, _T ("") und alle _tXXXXXX-Aufrufe usw.) zu vergessen und einfach überall Unicode anzunehmen. Ich sehe keinen Sinn darin, portabel zu sein, wenn Sie nie eine ANSI-Version benötigen. Ich würde alle breiten Zeichenfunktionen und -typen direkt verwenden. Stellen Sie alle Zeichenfolgenliterale mit einem L vor.

Erdferkel
quelle
3
Möglicherweise schreiben Sie Code, den Sie an einer anderen Stelle verwenden möchten, an der Sie eine ANSI-Version benötigen, oder (wie Nick sagte) Windows wechselt möglicherweise zu DCHAR oder was auch immer. Daher halte ich es immer noch für eine sehr gute Idee, stattdessen TCHAR zu verwenden WCHAR.
Arke
Ich bezweifle, dass Windows jemals zu UTF-32 wechseln wird.
Dan04
7
-1 für UTF-16-Empfehlung. Dadurch wird nicht nur nicht portabler (Windows-zentrierter) Code erstellt, der für Bibliotheken nicht akzeptabel ist - auch wenn er für die einfachsten Fälle wie UI-Code verwendet werden kann -, er ist selbst unter Windows selbst nicht effizient. utf8everywhere.org
Pavel Radzivilovsky
11

In dem Artikel Einführung in die Windows-Programmierung auf MSDN heißt es

Neue Anwendungen sollten immer die Unicode-Versionen (der API) aufrufen.

Die Makros TEXT und TCHAR sind heute weniger nützlich, da alle Anwendungen Unicode verwenden sollten.

Ich würde mich an wchar_tund halten L"".

Steven
quelle
4
Steven, Sie zitieren einen Text, der von jemandem geschrieben wurde, der die Bedeutung des Wortes "Unicode" nicht versteht. Es ist eines dieser unglücklichen Dokumente aus der Zeit der UCS-2-Verwirrung.
Pavel Radzivilovsky
2
@PavelRadzivilovsky: Das Dokument wurde für ein System geschrieben, in dem Unicode und UTF-16LE häufig synonym verwendet werden. Obwohl technisch ungenau, ist es dennoch eindeutig. Dies wird auch in der Einleitung desselben Textes ausdrücklich erwähnt: "Windows repräsentiert Unicode-Zeichen mit UTF-16-Codierung [...]" .
Unsichtbarer
11

Ich möchte einen anderen Ansatz vorschlagen (keiner der beiden).

Verwenden Sie zusammenfassend char * und std :: string unter der Annahme einer UTF-8-Codierung und führen Sie die Konvertierungen in UTF-16 nur durch, wenn Sie API-Funktionen einschließen.

Weitere Informationen und Begründungen für diesen Ansatz in Windows-Programmen finden Sie unter http://www.utf8everywhere.org .

Pavel Radzivilovsky
quelle
@PavelRadzivilovsky, würden wir bei der Implementierung Ihres Vorschlags in einer VC ++ - Anwendung den VC ++ - Zeichensatz auf "Keine" oder "Multibyte (MBCS)" setzen? Der Grund, den ich frage, ist, dass ich gerade Boost :: Locale installiert habe und der Standardzeichensatz MBCS war. FWIW, meine reine ASCII-Anwendung wurde auf 'Keine' gesetzt und ich habe sie jetzt auf 'MBCS' gesetzt (da ich Boost :: Locale darin verwenden werde) und es funktioniert einwandfrei. Bitte beraten.
Caroline Beltran
Wie utf8everywhere empfiehlt, würde ich es auf "Unicode-Zeichensatz verwenden" setzen. Dies bietet zusätzliche Sicherheit, ist jedoch nicht erforderlich. Der Autor von Boost :: locale ist ein sehr kluger Kerl, ich bin mir jedoch sicher, dass er das Richtige getan hat.
Pavel Radzivilovsky
1
Das UTF-8 Everywhere- Mantra wird nicht zur richtigen Lösung, nur weil es häufiger wiederholt wird. UTF-8 ist zweifellos eine attraktive Codierung für die Serialisierung (z. B. Dateien oder Netzwerk-Sockets). Unter Windows ist es jedoch häufig besser, Zeichendaten mithilfe der nativen UTF-16-Codierung intern zu speichern und an der Anwendungsgrenze zu konvertieren. Ein Grund ist, dass UTF-16 die einzige Codierung ist, die sofort in eine andere unterstützte Codierung konvertiert werden kann. Dies ist bei UTF-8 nicht der Fall.
Unsichtbarer
"..UTF-16 ist die einzige Codierung, die sofort in eine andere unterstützte Codierung konvertiert werden kann." Was meinst du? Was ist das Problem beim Konvertieren der UTF-8-Codierung in etwas anderes?
Pavel Radzivilovsky
1
Ich verstehe nicht. Zu irgendetwas anderem - wie was? ZB UCS-4? Warum nicht? Scheint sehr einfach, alle numerischen Algorithmus ..
Pavel Radzivilovsky
7

TCHARIch WCHARkönnte für einige Legacy-Projekte ausreichen. Aber für neue Anwendungen würde ich NEIN sagen .

Alle dieser TCHAR/ WCHARSachen sind da , weil die historischen Gründe. TCHARbietet eine scheinbar saubere Möglichkeit (Verkleidung), zwischen ANSI-Textcodierung (MBCS) und Unicode-Textcodierung (UTF-16) zu wechseln. In der Vergangenheit hatten die Menschen kein Verständnis für die Anzahl der Zeichen aller Sprachen der Welt. Sie nahmen an, dass 2 Bytes ausreichen, um alle Zeichen darzustellen, und daher ein Zeichencodierungsschema mit fester Länge verwenden WCHAR. Dies gilt jedoch nicht mehr nach der Veröffentlichung von Unicode 2.0 im Jahr 1996 .

Das heißt: Unabhängig davon, was Sie in CHAR/ WCHAR/ verwenden TCHAR, sollte der Textverarbeitungsteil in Ihrem Programm in der Lage sein, Zeichen variabler Länge zu verarbeiten für die Internationalisierung zu verarbeiten.

Sie müssen also tatsächlich mehr tun, als eine aus CHAR/ WCHAR/ TCHARfür die Programmierung in Windows auszuwählen:

  1. Wenn Ihre Anwendung klein ist und keine Textverarbeitung umfasst (dh nur die Textzeichenfolge als Argumente weitergibt), bleiben Sie bei WCHAR. Da es auf diese Weise einfacher ist, mit WinAPI mit Unicode-Unterstützung zu arbeiten.
  2. Andernfalls würde ich vorschlagen, UTF-8 als interne Codierung zu verwenden und Texte in Zeichenfolgen oder std :: string zu speichern. Und verdecken Sie sie auf UTF-16, wenn Sie WinAPI aufrufen. UTF-8 ist jetzt die dominierende Codierung und es gibt viele praktische Bibliotheken und Tools zum Verarbeiten von UTF-8-Zeichenfolgen.

Weitere Informationen finden Sie auf dieser wunderbaren Website: http://utf8everywhere.org/

Leopard
quelle
2
"UTF-8 ist jetzt die dominierende Codierung" - Dies wurde falsch, indem der zweite Teil des Zitats ( "für das World Wide Web" ) weggelassen wurde . Für Desktop-Anwendungen ist die am häufigsten verwendete native Zeichencodierung wahrscheinlich immer noch UTF-16. Windows verwendet es, Mac OS X ebenso wie die Zeichenfolgentypen von .NET und Java. Das macht eine enorme Menge an Code da draußen aus. Versteh mich nicht falsch, es gibt nichts Falsches an UTF-8 für die Serialisierung. Meistens (insbesondere unter Windows) ist die interne Verwendung von UTF-16 jedoch angemessener.
Unsichtbarer
4

Ja absolut; Zumindest für das _T-Makro. Ich bin mir allerdings nicht so sicher, was die Charaktere angeht.

Der Grund dafür ist, WinCE oder andere nicht standardmäßige Windows-Plattformen besser zu unterstützen. Wenn Sie zu 100% sicher sind, dass Ihr Code auf NT verbleibt, können Sie wahrscheinlich nur reguläre C-String-Deklarationen verwenden. Es ist jedoch am besten, sich dem flexibleren Ansatz zuzuwenden, da es viel einfacher ist, dieses Makro auf einer Nicht-Windows-Plattform zu definieren, als Tausende von Codezeilen zu durchlaufen und es überall hinzuzufügen, falls Sie eine Bibliothek portieren müssen zu Windows Mobile.

Nik Reiman
quelle
1
WinCE verwendet genau wie Win32 16-Bit-Zeichenfolgen wchar_t. Wir haben eine große Codebasis, die unter WinCE und Win32 ausgeführt wird, und wir verwenden niemals TCHAR.
Mhenry1384
2

IMHO, wenn Ihr Code TCHARs enthält, arbeiten Sie auf der falschen Abstraktionsebene.

Verwenden Sie was auch immer String - Typ ist für Sie am bequemsten , wenn sie mit Textverarbeitung zu tun - das wird hoffentlich etwas unterstützt Unicode sein, aber das ist bei Ihnen. Führen Sie die Konvertierung nach Bedarf an den Grenzen der Betriebssystem-API durch.

Erstellen Sie beim Umgang mit Dateipfaden Ihren eigenen benutzerdefinierten Typ, anstatt Zeichenfolgen zu verwenden. Dies ermöglicht Ihnen betriebssystemunabhängige Pfadtrennzeichen, bietet Ihnen eine einfachere Schnittstelle zum Codieren als manuelle Verkettung und Aufteilung von Zeichenfolgen und ist viel einfacher an verschiedene Betriebssysteme anzupassen (ansi, ucs-2, utf-8, was auch immer). .

Snemarch
quelle
Unicode verfügt über mindestens drei aktuelle Codierungen (UTF-8, UTF-16, UTF-32) und eine veraltete Codierung (UCS-2, eine Teilmenge der heutigen UTF-16). Auf welches beziehen Sie sich? Ich mag den Rest der Vorschläge, obwohl +1
0xC0000022L
2

Die einzigen Gründe, warum ich etwas anderes als das explizite WCHAR verwende, sind Portabilität und Effizienz.

Wenn Sie Ihre endgültige ausführbare Datei so klein wie möglich halten möchten, verwenden Sie char.

Wenn Sie sich nicht für die RAM-Nutzung interessieren und möchten, dass die Internationalisierung so einfach wie die einfache Übersetzung ist, verwenden Sie WCHAR.

Wenn Sie Ihren Code flexibel gestalten möchten, verwenden Sie TCHAR.

Wenn Sie nur die lateinischen Zeichen verwenden möchten, können Sie auch die ASCII / MBCS-Zeichenfolgen verwenden, damit Ihr Benutzer nicht so viel RAM benötigt.

Sparen Sie sich für Leute, die "i18n von Anfang an" sind, den Quellcode-Speicherplatz und verwenden Sie einfach alle Unicode-Funktionen.

Trololol
quelle
-1

Nur zu einer alten Frage hinzufügen:

NEIN

Starten Sie ein neues CLR C ++ - Projekt in VS2010. Microsoft selbst verwenden " L"Hello World", sagte Nuff.

kizzx2
quelle
13
Die CLR ist eine ganz andere Umgebung als nicht verwalteter Code. Das ist kein Argument.
Cody Gray
3
Auch Microsoft macht Fehler.
Pavel Radzivilovsky
6
-1 Die Frage ist markiert Cund C++. Antworten können jederzeit von den jeweiligen Autoren gelöscht werden. Dies wäre ein guter Zeitpunkt, um diese Bestimmung zu nutzen.
Unsichtbarer
-1

TCHARhaben eine neue Bedeutung zu portieren von WCHARnach CHAR.

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

In neueren Versionen von Windows 10 wurden die ANSI-Codepage und -A-APIs verwendet, um Apps mit UTF-8-Unterstützung zu versorgen. Wenn die ANSI-Codepage für UTF-8 konfiguriert ist, werden -A-APIs in UTF-8 ausgeführt.

OwnageIsMagic
quelle