C11 & C ++ 11 Ausgedehnte und universelle Charakterentweichung

8

Kontext

C11 und C ++ 11 unterstützen sowohl erweiterte Zeichen in Quelldateien als auch universelle Zeichennamen (Universal Character Names, UCNs), die es ermöglichen, Zeichen einzugeben, die nicht im Basis-Quellzeichensatz enthalten sind und nur Zeichen verwenden, die

sind

C ++ 11 definiert auch mehrere Übersetzungsphasen der Kompilierung. Insbesondere werden erweiterte Zeichen in der allerersten Übersetzungsphase, die im Folgenden beschrieben wird, auf UCNs normiert:

§ C ++ 11 2.2p1.1:

  

Physische Quelldateizeichen werden in einem   implementierungsdefinierter Art und Weise, zum grundlegenden Quellzeichensatz   (Einführung neuer Zeilenzeichen für Zeilenende-Indikatoren) if   notwendig. Die Menge der akzeptierten physischen Quelldateizeichen ist   Implementierung definiert. Die Trigrafsequenzen (2.4) werden ersetzt durch   entsprechende interne Ein-Zeichen-Darstellungen. Jede Quelle   Dateizeichen nicht im Basisquellzeichensatz (2.3) wird ersetzt   durch den universellen Charakternamen, der dieses Zeichen bezeichnet. (Ein   Implementation kann jede interne Kodierung verwenden, solange sie aktuell ist   erweitertes Zeichen in der Quelldatei gefunden, und das gleiche   erweitertes Zeichen, das in der Quelldatei als a ausgedrückt wird   Universal-Charaktername (d. h. unter Verwendung der \ uXXXX-Notation)   äquivalent behandelt, außer wenn diese Ersetzung in a zurückgenommen wird   Raw-String-Literal.)

Frage

Meine Frage lautet daher:

  

Ergibt eine standardkonforme Kompilierung des Programms

%Vor%      

fehlgeschlagen, kompilieren und drucken

%Vor%      

oder kompilieren und drucken

%Vor%      

, wenn ausgeführt?

Informierte persönliche Meinung

Es ist meine Behauptung, dass die Antwort darin besteht, dass es \u00e9 erfolgreich kompiliert und druckt, denn nach §2.2pl1.1 oben haben wir

Eine Implementierung kann eine interne Codierung verwenden, so lange ein tatsächliches erweitertes Zeichen in der Quelldatei gefunden wird , und dasselbe erweiterte Zeichen, das in der Quelldatei als universal angegeben ist -character-name (dh mit der \ uXXXX-Schreibweise ) wird äquivalent behandelt, außer wenn diese Ersetzung in einem Raw-String-Literal zurückgesetzt wird. , und wir sind nicht in einem rohen String-Literal.

Es folgt dann das

  • In Phase 1 wird printf("\é\n"); auf printf("\u00e9\n"); .
  • abgebildet
  • In Phase 3 Die Quelldatei wird in vorverarbeitende Token (§2.2p1.3) zerlegt, von denen das String-Literal "\u00e9\n" eins ist.
  • In Phase 5 wird jedes Quellenzeichensatzelement in einem Zeichenliteral oder einem Zeichenfolgenliteral sowie jede Escape-Sequenz und Universalzeichen-Name in einem Zeichenliteral oder einem Nicht-Raw-Zeichenfolgenliteral konvertiert an das entsprechende Mitglied des Ausführungszeichensatzes (§2.2p1.5). Nach dem Maximum-Munch-Prinzip wird also \ auf \ abgebildet, und das Fragment u00e9 wird nicht als UCN erkannt und druckt daher wie es ist.

Experimente

Bedauerlicherweise stimmen die existierenden Compiler mit mir nicht überein. Ich habe sowohl mit GCC 4.8.2 als auch mit Clang 3.5 getestet, und hier haben sie mir Folgendes gegeben:

  • GCC 4.8.2

    %Vor%
  • Clang 3.5

    %Vor%

Ich habe double- and-triple überprüft, dass das Zeichen é in Übereinstimmung mit der erwarteten UTF-8-Codierung als C3 A9 unter Verwendung von hexdump -C ucn.cpp angezeigt wird. Ich habe darüber hinaus überprüft, dass eine einfache printf("é\n"); oder printf("\u00e9\n"); einwandfrei funktioniert, so ist dies kein Problem der getesteten Compiler, UTF-8-Quelldateien nicht lesen zu können.

Wer hat Recht?

    
Iwillnotexist Idonotexist 10.05.2015, 16:38
quelle

2 Antworten

2

'é' ist kein gültiges Zeichen für Backslash-Escape in einem String-Literal. Daher sollte ein umgekehrter Schrägstrich gefolgt von 'é' als literales Quellzeichen oder UCN ein Compiler-Diagnose- und undefiniertes Verhalten erzeugen.

Beachten Sie jedoch, dass "\u00e9" kein UCN ist, dem ein umgekehrter Schrägstrich vorausgeht, und dass es nicht möglich ist, eine Folge von grundlegenden Quellzeichen in eine Zeichenfolge oder ein Zeichenliteral zu schreiben, das ein umgekehrter Schrägstrich gefolgt von einem UCN ist. Daher müssen sich "\é" und "\u00e9" nicht gleich verhalten: Das Verhalten von "\u00e9" kann perfekt definiert werden, während das Verhalten von "\é" nicht definiert ist.

Wenn wir eine Syntax setzen würden, die es einem Backslash erlaubt, einem UCN zu entkommen, sagen wir "\«\u00e9»" , dann hätte das undefiniertes Verhalten wie "\é" .

  
  • In Phase 1 wird printf("\é\n"); auf printf("\u00e9\n"); .
  • abgebildet   

Die Konvertierung von é in ein UCN in Phase 1 kann kein Nicht-UCN wie "\u00e9" erstellen.

Die Compiler haben recht, aber behandeln diese Situation nicht mit perfekten Diagnosemeldungen. Im Idealfall erhalten Sie:

%Vor%

Beide Compiler geben an, dass ihr Verhalten bei einer unbekannten Escape-Sequenz die Escapesequenz durch das so gematchte Zeichen ersetzt, sodass "\é" wie "é" behandelt würde und das Programm insgesamt wie folgt interpretiert werden sollte:

%Vor%

Beide Compiler bekommen dieses Verhalten teilweise zufällig, aber auch teilweise, weil die Richtlinie, unerkannte Escape-Sequenzen so zu behandeln, wie sie es tun, eine kluge Wahl ist: Obwohl sie nur die unerkannte Escape-Sequenz als umgekehrten Schrägstrich sehen Beim Byte 0xC3 entfernen sie den umgekehrten Schrägstrich und lassen die 0xC3 an ihrem Platz, was bedeutet, dass die UTF-8-Sequenz für die spätere Verarbeitung intakt bleibt.

    
bames53 10.05.2015, 21:13
quelle
1

Sie scheinen verwirrt zu sein und denken, dass \u00e9 eine UCN ist - das ist es nicht. UCNs beginnen alle mit \u , und in Ihrem Fall haben Sie einen Backslash zum Extrahieren, der diesen anfänglichen Backslash vermeidet. Also \u00e9 ist die Folge von 6 Zeichen: \ , u , 0 , 0 , e , 9 .

Bearbeiten

  

In Phase 1 printf ("\ é \ n"); maps to printf ("\ u00e9 \ n");.

Das ist der Punkt, an dem Sie falsch liegen - Phase 1 übersetzt Eingabezeichen in Quellzeichen, also printf("\é\n"); entspricht p r i n t f ( " \ é \ n " , das ist das gleiche wie ) ; p r i n t f ( " \ \u00e9 \ n " , aber das ist nicht das selbe wie was ) zuordnet, wegen des doppelten Backslash in letzterem. Aufgrund der speziellen Behandlung von Doppel-Backslash gibt es keine Möglichkeit, einen Backslash gefolgt von einem UCN in der Quelle zu haben.

    
Chris Dodd 10.05.2015 20:10
quelle

Tags und Links