K
Nur nochmal so als Nachtrag: Laut MSVC-Doku, verwendet der Compiler ASCII als execution character set und erwartet auch ASCII als Quellcode-Dateien. Dementsprechend kann man im ASCII-Quellcode auch kein 'Ä' unterbringen. Selbst ein '\u00CF' würde nicht funktionieren, da der Compiler es zum execution character set konvertieren müsste -- was nicht geht, da ASCII kein Ä enthält. Ich habe bis jetzt auch keine Optionen diesbezüglich gefunden. Eine mögliche Erklärung für die Originalfrage wäre also:
Der Compiler erwartet ASCII, unterstützt Ä offiziell also gar nicht, und prüft die Zeichen einfach nicht.
Der Quellcode liegt in ISO-8859-1 vor, dort hat das Ä den Code 0xC4
Der Compiler geht die ganze Zeit von ASCII aus. Und da auch das execution character set ASCII ist, muss nichts konvertiert werden und die 0xC4 bleibt erhalten.
char ist vorzeichenbehaftet und verwendet das 2er Komplement für negative Zahlen.
Der GCC-Doku kann man entnehmen, dass über die -finput-charset= Option festgelegt werden kann, wie Quellcodedateien kodiert wurden. Damit kann er auch Zeichen wie Ä verarbeiten. Teil der Übersetzung ist jedoch die Konvertierung in das execution character set. Das scheint unter WinXP beim g++ (tdm-1) 4.5.1 UTF-8 per Default zu sein, was auch erklärt, warum ich eine Multibyte-Warnung bekomme:
// Diesen Quellcode habe ich in UTF-8 gespeichert.
char foo() { return '\u00Cf'; }
char bar() { return 'Ä'; }
>g++ -c -Wall -finput-charset=UTF-8 test.cpp
test.cpp:2:21: warning: multi-character character constant
test.cpp:3:21: warning: multi-character character constant
test.cpp: In function 'char foo()':
test.cpp:2:21: warning: overflow in implicit constant conversion
test.cpp: In function 'char bar()':
test.cpp:3:21: warning: overflow in implicit constant conversion
(Dieselbe Ausgabe sieht man, wenn man -fexec-charset=UTF-8 verwendet). Klar, ein UTF-8-kodiertes Ä ist ja kein einzelnes Byte mehr. Mit ISO-8859-1 als exec-charset:
>g++ -c -Wall -finput-charset=UTF-8 -fexec-charset=ISO-8859-1 test.cpp
>
klappt das Ganze. Obwohl in der Quellcodedatei das Ä immernoch aus 2 Bytes besteht, konvertiert der Compiler dies zum "execution character set". Das ist in diesem Fall "single-byte" und die Warnungen verschwinden.
Da bei mir der Standard-CMD.exe-Zeichensatz Codepage 850 ist, habe ich mal probiert, ob ich als Zeichensatz einfach 850 eingeben kann und siehe da:
>g++ -c -Wall -finput-charset=UTF-8 -fexec-charset=850 test.cpp
>
Der Compiler schluckt es ohne Warnung. Ein Blick in das Ergebnis bringt aber etwas Ernüchterung:
>objdump -Cd test.o
test.o: file format pe-i386
Disassembly of section .text:
00000000 <foo()>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: b0 d8 mov [b]$0xd8[/b],%al
5: c9 leave
6: c3 ret
00000007 <bar()>:
7: 55 push %ebp
8: 89 e5 mov %esp,%ebp
a: b0 8e mov [b]$0x8e[/b],%al
c: c9 leave
d: c3 ret
Lediglich bar() liefert mir hier das erwartete Ergebnis; denn das Ä hat in der Codepage 850 den Code 0x8E. Was das 0xD8 hier zu suchen hat, weiß ich nicht. Ich gehe mal davon aus, dass es ein Bug ist; denn für Ä klappt es ja und der Standard verlangt, dass in dem Fall beide Versionen hätten äquivalent übersetzt werden müssen.
Obwohl der 2011er Standard immer noch nicht verlangt, dass ein Compiler UTF-8- und/oder UTF-16-kodierte Quelltexte lesen können muss, kann es sich meiner Meinung nach kein Hersteller erlauben, ein solches Feature nicht anzubieten; denn sonst würden die "Unicode-Literale" einfach keinen Spaß machen.
const char utf8_string_1[] = u8"H\u00E4nsel und Gretel"; // (1)
const char utf8_string_2[] = u8"Hänsel und Gretel"; // (2)
(1): 100% portabal in C++2011
(2): Der Compiler muss das ä lesen und verstehen können. Diese Fähigkeit ist optional.
Habe ich beim MSVC etwas übersehen bzgl Optionen?