Wieso ist 'Ä' -60 ?
-
SeppJ schrieb:
ASCIIIIIII schrieb:
Das kann man auch hoeflicher ausdruecken. Ich hab dich wohl kaum angegriffen?
Dann entschuldige ich mich vielmals. Namen machen Leute und dein Nickname erweckte bei mir den Eindruck, dass du nicht wirklich helfen wolltest, sondern bewusst falsche Tatsachen beschreiben hast.
Oh ok.
Nur koenntest du mir noch den falschen Teil meiner Aussage erlaeutern?
-
hans312 schrieb:
Nur koenntest du mir noch den falschen Teil meiner Aussage erlaeutern?
"Der Standard" a.k.a. "der C++ Standard" setzt ASCII nicht voraus.
-
cooky451 schrieb:
hans312 schrieb:
Nur koenntest du mir noch den falschen Teil meiner Aussage erlaeutern?
"Der Standard" a.k.a. "der C++ Standard" setzt ASCII nicht voraus.
Oh ok. [Siehe CStoll Post]
Danke fuer die Erlaeuterung
-
hans312 schrieb:
Nur koenntest du mir noch den falschen Teil meiner Aussage erlaeutern?
1. Es gibt keinen Standard, der dir die ersten 128 garantiert. Es gibt verschiedene Standards dafür, an welchen dein Computer sich hält, ist nicht festgelegt (ja, es ist ziemlich sicher, dass fast alle Computer ASCII benutzen, aber du kannst dir nicht 100% sicher sein, wenn du an einem beliebigen Computer in der Welt gesetzt wirst, dass dies so ist)
2. Für alles oberhalb von 128 gilt das gleiche. Auch hier gibt es Standards, an die sich ein Computer halten kann oder auch nicht und es gibt auch verschiedene und wenn du an einem beliebigen Computer in der Welt gesetzt wirst, kannst du nicht sicher sein, was der Fall ist.
Im Prinzip ist gilt für beide Zahlenbereiche das gleiche, nichts ist garantiert. Der Unterschied ist bloß, dass ASCII ein bisschen verbreiteter ist, als z.B. Unicode.
edit: Da war ich mal wieder zu langsam.
edit2: Und wenn ich schon am Editieren bin: Auf gewisse Sachen kann man sich schon verlassen. Zum Beispiel ist garantiert, dass ein in C geschriebenes Programm sich auf die Folge der Ziffern 0- 9 verlassen kann. Auf einem Computer bei dem das nicht so ist, kann kein (standardkonformer) C-Compiler laufen. Außerdem könnten bestimmte Betriebssysteme dir Garantien machen, bei DOS ist (bin mir nicht 100% sicher, aber ziemlich) zum Beispiel sicher, dass es ASCII benutzt.
-
Ist
char c = 'Ä';
überhaupt ein wohlgeformtes C++-Programm?
Ich weiß es gerade nicht. Ich kann mir gut aber vorstellen, dass es nicht unter die strenge Definition von "wohlgeformt" fällt, weil der Compiler die Bytes, die sich hinter dem Ä verstecken ja im allgemeinen nicht verstehen kann, weil der C++-Standard kein Encoding vorschreibt. Insbesondere weiß der Editor ja auch nicht, ob er das Ä nun für den C++-Compiler utf8-kodieren soll oder latin1 oder was auch immer.
-
Christoph schrieb:
Ist
char c = 'Ä';
überhaupt ein wohlgeformtes C++-Programm?
Interessante Frage! Der C++ Standard spricht hier von einem "source character set", welcher nur 96 Zeichen umfasst (a-z, A-Z, 0-9 und _{}[]#()<>%:;.?*+-/^&|~!=,\"'). Und wenn ich micht nicht verguckt habe, sind nur Zeichen aus diesem "source character set" in Char-Literals erlaubt.
-
krümelkacker schrieb:
Christoph schrieb:
Ist
char c = 'Ä';
überhaupt ein wohlgeformtes C++-Programm?
Interessante Frage! Der C++ Standard spricht hier von einem "source character set", welcher nur 96 Zeichen umfasst (a-z, A-Z, 0-9 und _{}[]#()<>%:;.?*+-/^&|~!=,\"'). Und wenn ich micht nicht verguckt habe, sind nur Zeichen aus diesem "source character set" in Char-Literals erlaubt.
Verzeihung, aber hier gefällt mir was nicht.
Denn ich habe damals, um mir das Prinzip der Zeichensätze, Codepages und Lokalen beizubringen, versucht, das System, wie die DOS-Konsole auf Windows meine hübschen Sätze mit Umlauten ruiniert, durchzublicken. In den Quellcode selbst darf man keine Zeichen einfügen, die nicht zwischen 32 und 127 liegen (es sei denn \r und \n - zumindest ist das bei VS so), aber man kann als Stringliteral sehr wohl Sonderzeichen 'Ä' oder 'ß' angeben.
Es scheint wohl so, dass der Wert, den das Zeichen in der gegenwärtigen Codepage (oder in Unicode) belegt, direkt reingeschrieben wird. Bei Codepage 1252 und einem 'Ä' würde in
c
dann 196 als Wert stehen. Wenn man nun verwegen oder ein Anfänger ist und das ganze unter der Eingabeaufforderung ausgibt, kommt nur das Zeichen '─' raus - weil dieses Zeichen in der Codepage 850 nun einmal den Wert 196 besitzt. Das Zeichen für 'Ä' wäre hier aber 142 ...Ich vermute also stark, dass der Wert des Zeichens einfach den Wert in der gegenwärtig ausgewählten Codepage annimmt.
-
Der aus dem Westen ... schrieb:
In den Quellcode selbst darf man keine Zeichen einfügen, die nicht zwischen 32 und 127 liegen (es sei denn \r und \n - zumindest ist das bei VS so), aber man kann als Stringliteral sehr wohl Sonderzeichen 'Ä' oder 'ß' angeben.
Es ging mir bei meiner Frage nicht darum, wie es ein bestimmter Compiler macht, oder wie es zu funktionieren scheint, sondern ob es ein wohlgeformtes C++-Programm im Sinne des C++-Standards ist.
krümelkackers Antwort nach ist es wohl tatsächlich kein wohlgeformtes C++-Programm.
-
Der aus dem Westen ... schrieb:
Verzeihung, aber hier gefällt mir was nicht. [...]
Du hast zwar nirgends Bezug auf den ISO/IEC 14882:2003 Standard genommen, mich aber doch dazu bekommen, dort nochmal nach zu gucken.
Es ist die Rede von 3 Zeichensätzen:
- basic source character set (Leerzeichen, horizontal-tab, vertical-tab, form-feed, new-line und 91 graphische Zeichen a-z, A-Z, 0-9 und _{}[]#()<>%:;.?*+-/^&|~!=,\"')
- physical source file character set (enthält das basic source character set)
- execution character set (enthält das basic source character set)
Ich hatte die ersten beiden in einen Topf geschmissen. Das war falsch.
In der ersten Phase der Übersetzung werden alle Zeichen aus der Quellcodedatei zu Zeichen aus dem Basic Source Character konvertiert. Trigraphs werden dabei auch ersetzt. Jedes Zeichen aus dem source character set, welches nicht um basic source character set ist, wird hier durch ein "universal-character-name" (\uNNNN oder \UNNNNNNNN wobei N der Unicode-Codepoint ist) ersetzt, der diesem Zeichem entspricht. Beispiel:
Ä --> \u00C4
Diesen universellen Namen muss der Compiler aber eigentlich richtig in das execution character set (ECS) übersetzen. Wenn das ECS jetzt die Codepage 850 sein sollte, dann müsste das Byte 0x8E im Executable zu finden sein.
Zitate aus dem Standard:
§2.1/1.1:
Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences (2.3) are replaced by corresponding single-character internal representations. Any source file character not in the basic source character set (2.2) is replaced by the universal-character-name that designates that character. (An implementation may use any internal encoding, so long as an actual extended character encountered in the source file, and the same extended character expressed in the source file as a universal-character-name (i.e. using the \uXXXX notation), are handled equivalently.)
§2.2
universal-character-name: \u hex-quad \U hex-quad hex-quad
§2.2/2
The character designated by the universal-character-name \UNNNNNNNN is that character whose character short name in ISO/IEC 10646 is NNNNNNNN; the character designated by the universal-character-name \uNNNN is that character whose character short name in ISO/IEC 10646 is 0000NNNN. If the hexadecimal value for a universal character name is less than 0x20 or in the range 0x7F-0x9F (inclusive), or if the universal character name designates a character in the basic source character set, then the program is illformed.
§2.13.2
character-literal: ’c-char-sequence’ L’c-char-sequence’ c-char-sequence: c-char c-char-sequence c-char c-char: any member of the source character set except the single-quote ’, backslash \, or new-line character escape-sequence universal-character-name
§2.13.2/5
A universal-character-name is translated to the encoding, in the execution character set, of the character named. If there is no such encoding, the universal-character-name is translated to an implementationdefined encoding. [Note: in translation phase 1, a universal-character-name is introduced whenever an actual extended character is encountered in the source text. Therefore, all extended characters are described in terms of universal-character-names. However, the actual compiler implementation may use its own native character set, so long as the same results are obtained. ]
-
Christoph schrieb:
Ist
char c = 'Ä';
überhaupt ein wohlgeformtes C++-Programm?
So wie ich das lese: nein.
char c = '\u00c4';
wäre in Ordnung, und einer Implementation steht es frei, Ersteres in Letzteres zu übersetzen.
-
camper schrieb:
Christoph schrieb:
Ist
char c = 'Ä';
überhaupt ein wohlgeformtes C++-Programm?
So wie ich das lese: nein.
char c = '\u00c4';
wäre in Ordnung, und einer Implementation steht es frei, Ersteres in Letzteres zu übersetzen.
Ich verstehe das etwas anders. Wenn ein Ä Teil des source character sets ist, dann hat diese "Übersetzung" stattzufinden. Der Wert von '\u00C4' ist aber meinem Verständnis nach durch das execution character set festgelegt. Also, angenommen das ECS ist "Codepage 850" und char is vorzeichenlos, dann verstehe ich das so, dass folgendes gelten müsste:
'\u00C4' == 0x8E
-
krümelkacker schrieb:
Es ist die Rede von 3 Zeichensätzen:
- basic source character set (Leerzeichen, horizontal-tab, vertical-tab, form-feed, new-line und 91 graphische Zeichen a-z, A-Z, 0-9 und _{}[]#()<>%:;.?*+-/^&|~!=,\"')
- source character set (enthält das basic source character set)
- execution character set (enthält das basic source character set)
Ich sehe im Standard nirgendwo ein source character set das nicht das basic source character set ist.
'Ä' ist kein Teil davon.
-
camper schrieb:
krümelkacker schrieb:
Es ist die Rede von 3 Zeichensätzen:
- basic source character set (Leerzeichen, horizontal-tab, vertical-tab, form-feed, new-line und 91 graphische Zeichen a-z, A-Z, 0-9 und _{}[]#()<>%:;.?*+-/^&|~!=,\"')
- physical source file character set (enthält das basic source character set)
- execution character set (enthält das basic source character set)
Ich sehe im Standard nirgendwo ein source character set das nicht das basic source character set ist.
'Ä' ist kein Teil davon.
§2.1/1
Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences (2.3) are replaced by corresponding single-character internal representations. Any source file character not in the basic source character set (2.2) is replaced by the universal-character-name that designates that character. (An implementation may use any internal encoding, so long as an actual extended character encountered in the source file, and the same extended character expressed in the source file as a universal-character-name (i.e. using the \uXXXX notation), are handled equivalently.)
Nach dieser Phase gibt es keine Zeichen mehr, die nicht im "basic character set" sind; denn ein universal-character-name besteht aus Zeichen, die aus dem basic source character set kommen (Beispiel: \u00C4, also Backslash, u und HexQuad). Von daher braucht der Rest des Standards da auch nicht mehr drauf eingehen. Der Zeichensatz der Eingabedatei könnte ein Ä enthalten; denn, was das für ein erweiterter Zeichensatz ist, wurde nicht näher beschrieben und die letzte unterstrichene Stelle im zitierten Text macht klar, dass auch Zeichen vorkommen können, die nicht im basic source character set enthalten sind. Die werden dann eben nur durch ein universal-character-name ersetzt.
Die Definition von "well-formed" habe ich jetzt nicht im Kopf. Aber, wenn man weiß, dass die C++ Implementierung, die man nutzt, Quellcodedateien zB mit ISO-8859-1-, UTF-8-- oder UTF-16-Kodierung lesen und verstehen kann, dann darf natürlich auch ein 'Ä' im Quellcode auftauchen. Das, was am Ende rauskommt, ist äquivalent zu dem, was man bekommen würde, hätte man stattdessen '\u00C4' geschrieben.
Dem GCC kann man über eine Option sagen, was für eine Zeichenkodierung benutzt worden ist:
[...]
The character sets of the input files are specified using the -finput-charset= option.All preprocessing work (the subject of the rest of this manual) is carried out in the source character set. If you request textual output from the preprocessor with the -E option, it will be in UTF-8.
[...]Edit:
Ich sehe gerade, dass sogar universelle Zeichennamen in Bezeichnern erlaubt sind. Theoretisch wäre dann auch so etwas möglich:void föö();
Aber der GCC unterstützt das zB nicht.
Edit2:
LOL. In C++2011 werden universal character names nicht mehr in Bezeichnern unterstützt. Interessant.
-
Das wäre doch auch irgendwie doof, wenn das Programmverhalten (oder schlimmer noch, ob es sich überhaupt übersetzten lässt) eines standardkonformen Programms von der Zeichencodierung auf der Maschine auf der ich das Programm übersetzt habe, abhinge.
-
krümelkacker schrieb:
camper schrieb:
krümelkacker schrieb:
Es ist die Rede von 3 Zeichensätzen:
- basic source character set (Leerzeichen, horizontal-tab, vertical-tab, form-feed, new-line und 91 graphische Zeichen a-z, A-Z, 0-9 und _{}[]#()<>%:;.?*+-/^&|~!=,\"')
- physical source file character set (enthält das basic source character set)
- execution character set (enthält das basic source character set)
Ich sehe im Standard nirgendwo ein source character set das nicht das basic source character set ist.
'Ä' ist kein Teil davon.
§2.1/1
Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences (2.3) are replaced by corresponding single-character internal representations. Any source file character not in the basic source character set (2.2) is replaced by the universal-character-name that designates that character. (An implementation may use any internal encoding, so long as an actual extended character encountered in the source file, and the same extended character expressed in the source file as a universal-character-name (i.e. using the \uXXXX notation), are handled equivalently.)
Nach dieser Phase gibt es keine Zeichen mehr, die nicht im "basic character set" sind; denn ein universal-character-name besteht aus Zeichen, die aus dem basic source character set kommen (Beispiel: \u00C4, also Backslash, u und HexQuad). Von daher braucht der Rest des Standards da auch nicht mehr drauf eingehen. Der Zeichensatz der Eingabedatei könnte ein Ä enthalten; denn, was das für ein erweiterter Zeichensatz ist, wurde nicht näher beschrieben und die letzte unterstrichene Stelle im zitierten Text macht klar, dass auch Zeichen vorkommen können, die nicht im basic source character set enthalten sind. Die werden dann eben nur durch ein universal-character-name ersetzt.
Ok. source file character set also.
Das ist allerdings trotzdem keine Übermenge des basic character sets.
1. Nicht alle Maschinen vefügen überhaupt physisch über alle Zeichen des baisc character sets. Andernfalls gäbe es auch keinen Grund, Di- und Trigraphen zu haben.
2. Zweitens ist das Mapping implementation-defined - es wird keine 1:1 Äquivalenz gefordert. Z.B. wird nicht bestimmt, dass Unicode Äquivalenz zum gleichen Zeichen führen muss.Meiner Ansicht nach ist die Frage, ob ein Programm wohlgeformt ist (ein undefinierter Begriff, denn man einfach als Negation von ill-formed einführen kann), nicht sinnvoll zu beantworten, bevor die Übersetzung in das basic character set stattgefunden hat.
-
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?