Weil ich gebeten wurde, werde ich etwas Nekromantie machen. Die anderen Antworten stammen aus dem Jahr 2009, aber dieser Artikel wird immer noch bei einer Suche angezeigt, die ich 2018 gemacht habe. Die Situation heute ist sehr unterschiedlich. Auch die akzeptierte Antwort war schon 2009 unvollständig.
Der Quellzeichensatz
Jeder Compiler (einschließlich Microsofts Visual Studio 2008 und später, gcc, clang und icc) wird UTF-8-Quelldateien mit BOM ohne Probleme lesen, und clang wird nichts anderes als UTF-8 lesen, daher ist UTF-8 mit BOM das kleinste gemeinsame Vielfache für C- und C++-Quelldateien.
Der Sprachstandard sagt nicht, welche Zeichencodierungen der Compiler unterstützen muss. Einige real existierende Quelldateien sind sogar in einem Zeichensatz gespeichert, der nicht mit ASCII kompatibel ist. Microsoft Visual C++ unterstützte 2008 UTF-8-Quelldateien mit einer Byte-Reihenfolge-Markierung sowie beide Formen von UTF-16. Ohne Byte-Reihenfolge-Markierung würde es annehmen, dass die Datei im aktuellen 8-Bit-Zeichensatz codiert ist, der immer eine Erweiterung von ASCII war.
Die Ausführungszeichensätze
Im Jahr 2012 fügte der Compiler einen /utf-8
-Schalter zu CL.EXE
hinzu. Heute unterstützt er auch die Schalter /source-charset
und /execution-charset
sowie /validate-charset
, um festzustellen, ob Ihre Datei tatsächlich nicht UTF-8 ist. Diese Seite auf MSDN enthält einen Link zur Dokumentation zur Unicode-Unterstützung für jede Version von Visual C++.
Aktuelle Versionen des C++-Standards besagen, dass der Compiler sowohl einen Ausführungszeichensatz haben muss, der den numerischen Wert von Zeichenkonstanten wie 'a'
bestimmt, als auch einen Ausführungszeichensatz für Breitzeichen, der den Wert von Breitzeichenkonstanten wie L'é'
bestimmt.
Etwas gesetzestreue Sprache für einen Moment, es gibt sehr wenige Anforderungen im Standard, wie diese codiert sein müssen, und doch schaffen es Visual C und C++, dagegen zu verstoßen. Es muss etwa 100 Zeichen enthalten, die keine negativen Werte haben können, und die Codierungen der Ziffern '0'
bis '9'
müssen aufeinanderfolgend sein. Weder Groß- noch Kleinbuchstaben müssen es sein, da sie auf einigen alten Großrechnern nicht waren. (Das heißt, '0'+9
muss dasselbe wie '9'
sein, aber es gibt immer noch einen Compiler, der heute in der realen Welt verwendet wird, bei dem das Standardverhalten ist, dass 'a'+9
nicht 'j'
ist, sondern '«'
, und das ist legal.) Der Breitzeichen-Ausführungssatz muss den grundlegenden Ausführungssatz enthalten und genügend Bits haben, um alle Zeichen jeder unterstützten Ländereinstellung zu speichern. Jeder gängige Compiler unterstützt mindestens eine Unicode-Ländereinstellung und versteht gültige Unicode-Zeichen, die mit \Uxxxxxxxx
angegeben sind, aber ein Compiler, der dies nicht tut, könnte behaupten, dem Standard zu entsprechen.
Visual C und C++ verletzen den Sprachstandard, indem sie ihr wchar_t
als UTF-16 definieren, das nur einige Zeichen als Ersatzpaare darstellen kann, obwohl der Standard besagt, dass wchar_t
eine festbreite Codierung sein muss. Das liegt daran, dass Microsoft das wchar_t
in den 1990er Jahren als 16 Bits breit definiert hat, bevor das Unicode-Komitee feststellte, dass 16 Bits nicht für die gesamte Welt ausreichen würden und Microsoft die Windows-API nicht ändern wollte. Es unterstützt auch den standardmäßigen char32_t
-Typ.
UTF-8-Zeichenkettenliterale
Das dritte Problem, das diese Frage aufwirft, ist, wie man den Compiler dazu bringt, einen Zeichenkettenliteral im Speicher als UTF-8 zu codieren. Seit C++11 können Sie etwas wie folgt schreiben:
constexpr unsigned char hola_utf8[] = u8"¡Hola, mundo!";
Dies codiert die Zeichenkette als ihre mit einem Nullzeichen terminierte UTF-8-Byte-Repräsentation, unabhängig davon, ob der Quellzeichensatz UTF-8, UTF-16, Latin-1, CP1252 oder sogar IBM EBCDIC 1047 ist (was ein lächerliches theoretisches Beispiel ist, aber dennoch aus Gründen der Abwärtskompatibilität auf dem IBM-Z-Series-Großrechner-Compiler voreingestellt ist). Das heißt, es ist gleichwertig mit der Initialisierung des Arrays mit { 0xC2, 0xA1, 'H', /* ... , */ '!', 0 }
.
Wenn es zu umständlich wäre, ein Zeichen einzugeben, oder wenn Sie zwischen oberflächlich identischen Zeichen wie Leerzeichen und geschützten Leerzeichen oder vorkomponierten und kombinierten Zeichen unterscheiden möchten, haben Sie auch universelle Zeichenescapes:
constexpr unsigned char hola_utf8[] = u8"\u00a1Hola, mundo!";
Sie können diese unabhängig vom Quellzeichensatz und unabhängig davon, ob Sie das Literal als UTF-8, UTF-16 oder UCS-4 speichern, verwenden. Sie wurden ursprünglich in C99 hinzugefügt, aber Microsoft unterstützte sie in Visual Studio 2015.
Bearbeitung: Wie von Matthew berichtet, sind u8"
-Zeichenfolgen in einigen Versionen von MSVC fehlerhaft, einschließlich 19.14. Es stellt sich heraus, auch literale Nicht-ASCII-Zeichen, auch wenn Sie /utf-8
oder /source-charset:utf-8 /execution-charset:utf-8
angeben. Der obige Beispielcode funktioniert ordnungsgemäß in 19.22.27905.
Es gibt noch einen anderen Weg, dies zu tun, der in Visual C oder C++ 2008 funktionierte: Oktal- und Hexadezimalescape-Codes. Sie hätten UTF-8-Literale in dieser Version des Compilers so codiert:
const unsigned char hola_utf8[] = "\xC2\xA1Hello, world!";
0 Stimmen
Can you give us a little bit more input. Is this happening for build output, all output or something else? Can you give us a specific operation for which this happens (build, debugging, etc ...)
0 Stimmen
Ja, bitte zeigen Sie ein Beispiel dafür, was Ihrer Meinung nach erscheinen sollte und was tatsächlich erscheint.
1 Stimmen
Was passiert, wenn Sie wcout verwenden?
0 Stimmen
Es ist praktisch in allen Ausgaben. Debug, Build, Watcher, usw.
0 Stimmen
@Naveen: Kein Erfolg, ändert nichts.
1 Stimmen
Ich bin mir nicht sicher, aber ich glaube, du solltest _T() oder L"" verwenden, um Unicode-Zeichenfolgen in Visual Studio zu spezifizieren. Kannst du das einmal mit wcout ausprobieren?
0 Stimmen
@Naveen: Ich habe
L"àéêù"
ausprobiert, leider ohne Erfolg. Ich bin mir nicht sicher, wie _T() funktioniert... Kannst du bitte ein konkretes Beispiel geben?0 Stimmen
Es wird als _T("naveen") verwendet, aber ich erwarte nicht, dass es funktioniert, da L"" nicht funktioniert. Vielleicht ein anderes Problem..
1 Stimmen
Warum verwenden Sie nicht breite Zeichenfolgen? So implementiert Windows die Unicode-Unterstützung.
0 Stimmen
Alle Zeichen der französischen Sprache werden ohne Unicode als erweitertes Ascii unterstützt. Deshalb verwende ich kein Unicode, ich sollte es nicht brauchen.
0 Stimmen
Windows versteht kein "Erweitertes ASCII". Es versteht nur lokalspezifische Codepages (wahrscheinlich Standardwerte 1252 für Ihren Computer) und Unicode.
2 Stimmen
Seitdem diese Antwort 2018 bei einer Google-Suche erschienen ist, werde ich einen Kommentar hinterlassen. C++11 oder später unterstützt UTF-8 für den Ausführungszeichensatz mit
u"..."
. Visual C++ 2008 unterstützte UTF-8 mit BOM als Quellenzeichensatz, und aktuelle Versionen unterstützen es ohne BOM mit dem/UTF-8
-Schalter. Andere Compiler, einschließlich gcc, clang und icc, unterstützen es ebenfalls. Der Sprachstandard erlaubt seit Jahren, dass Compiler beliebige Quell- und Ausführungszeichensätze unterstützen, solange sie eine minimale Anzahl von Grundzeichen enthalten.0 Stimmen
@Davislor Vielen Dank dafür! Könntest du das als Antwort schreiben? Das ist sicherlich relevant und würde Aufmerksamkeit darauf lenken.
0 Stimmen
@MPelletier Erledigt. Vielleicht ein wenig übertrieben.