Erstellen von Bezeichnern mit universellen Zeichennamen über Token-Verkettung

Lesezeit: 4 Minuten

Benutzer-Avatar
MikeCAT

Ich habe diesen Code geschrieben, der Bezeichner erstellt, die universelle Zeichennamen über Token-Verkettung enthalten.

//#include <stdio.h>
int printf(const char*, ...);

#define CAT(a, b) a ## b

int main(void) {
    //int \u306d\u3053 = 10;
    int CAT(\u306d, \u3053) = 10;

    printf("%d\n", \u306d\u3053);
    //printf("%d\n", CAT(\u306d, \u3053));

    return 0;
}

Dieser Code funktionierte gut mit gcc 4.8.2 mit -fextended-identifiers Möglichkeit und gcc 5.3.1funktionierte aber nicht mit klingen 3.3 mit Fehlermeldung:

prog.c:10:17: error: use of undeclared identifier 'ねこ'
        printf("%d\n", \u306d\u3053);
                       ^
1 error generated.

und lokaler Clang (Apple LLVM Version 7.0.2 (clang-700.1.81)) mit Fehlermeldung:

$ clang -std=c11 -Wall -Wextra -o uctest1 uctest1.c
warning: format specifies type 'int' but the argument has type
      '<dependent type>' [-Wformat]
uctest1.c:10:17: error: use of undeclared identifier 'ねこ'
        printf("%d\n", \u306d\u3053);
                       ^
1 warning and 1 error generated.

Als ich benutzte -E Option, den Compiler-Ausgabecode mit Makro erweitert zu haben, gab gcc 5.3.1 Folgendes aus:

# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.c"

int printf(const char*, ...);



int main(void) {

 int \U0000306d\U00003053 = 10;

 printf("%d\n", \U0000306d\U00003053);


 return 0;
}

local clang hat folgendes ausgegeben:

# 1 "uctest1.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 326 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "uctest1.c" 2

int printf(const char*, ...);



int main(void) {

 int \u306d\u3053 = 10;

 printf("%d\n", ねこ);


 return 0;
}

Wie Sie sehen, sind die deklarierten und verwendeten Bezeichner in printf() Übereinstimmungen in der Ausgabe von gcc, aber sie stimmen nicht mit der Ausgabe von clang überein.

Ich weiß, dass das Erstellen universeller Zeichennamen über Token-Verkettung undefiniertes Verhalten hervorruft.

Zitat aus N1570 5.1.1.2 Übersetzungsphasen:

Wenn durch Tokenverkettung (6.10.3.3) eine Zeichenfolge erzeugt wird, die der Syntax eines universellen Zeichennamens entspricht, ist das Verhalten undefiniert.

Ich dachte, dass diese Zeichenfolge \u306d\u3053 kann “mit der Syntax eines universellen Zeichennamens übereinstimmen”, da es universelle Zeichennamen als Teilzeichenfolge enthält. Ich dachte auch, dass “Match” bedeuten könnte, dass das gesamte durch Verkettung erzeugte Token für einen universellen Zeichennamen steht und dass dieses undefinierte Verhalten daher in diesem Code nicht aufgerufen wird.

Lektüre PRE30-C. Erstellen Sie keinen universellen Zeichennamen durch Verkettunghabe ich einen Kommentar gefunden, der besagt, dass diese Art der Verkettung erlaubt ist:

Was verboten ist, eine neue UCN per Verkettung zu erstellen. Wie tun

zuweisen(\u0001,0401,a,b,4)

Es ist in Ordnung, nur Dinge zu verketten, die zufällig irgendwo UCNs enthalten.

Und ein Protokoll, das das zeigt ein Codebeispiel wie in diesem Fall (aber mit 4 Zeichen) wird durch ersetzt noch ein Codebeispiel.

Ruft mein Codebeispiel einige undefinierte Verhaltensweisen auf (nicht beschränkt auf solche, die durch die Erzeugung universeller Zeichennamen über die Token-Verkettung aufgerufen werden)? Oder ist das ein Bug in Clang?

  • Soweit es mich betrifft, sieht der gcc 5.3.1 viel schlechter aus … kommentieren Sie das aus //printf("%d\n", CAT(\u306d, \u3053)); Linie und es beschwert sich. Mit clang bekomme ich zumindest konsistente Ergebnisse – ich kann alle Zeilen auskommentieren und es akzeptiert es, da das Ergebnis von using CAT unterscheidet sich konsequent von der direkten Verkettung.

    – grek40

    2. Mai 2016 um 17:05 Uhr

  • @grek40 gcc 6.1 beschwert sich nicht darüber, scheint ein aber in gcc 5.3.1 (nicht ausprobiert) ?

    – Benutzer1887915

    5. Mai 2016 um 4:46 Uhr

  • Trigraphen, Digraphen, UCN … sagen Sie einfach NEIN.

    – chqrlie

    5. Mai 2016 um 22:22 Uhr

Benutzer-Avatar
Benutzer1887915

Ihr Code löst nicht das von Ihnen erwähnte undefinierte Verhalten aus, da der universelle Zeichenname (6.4.3) nicht durch Tokenverkettung erzeugt wird.

Und gemäß 6.10.3.3 sowohl als linke als auch als rechte Seite des Bedieners ## ein Bezeichner ist, und das erzeugte Token auch ein gültiges Vorverarbeitungstoken ist (auch ein Bezeichner), der ## Operator selbst löst kein undefiniertes Verhalten aus.

Nachdem ich die Beschreibung über Bezeichner (6.4.2, D.1, D.2) und universelle Zeichennamen (6.4.3) gelesen habe, bin ich mir ziemlich sicher, dass es sich eher um einen Fehler im Clang-Präprozessor handelt, der vom Token erzeugte Bezeichner behandelt Verkettung und normaler Bezeichner unterschiedlich.

  • +1, genau das. 5.1.1.2 sagt nicht, dass Sie nicht ganze UCNs im Präprozessor manipulieren können; Es besagt, dass Sie UCNs nicht aus ihren Bestandteilen herstellen können (z. B. das Herstellen einer UCN als Folge von \U30 ## 53 ist illegal). Lange Rede kurzer Sinn, GCC macht das richtig und Clang nicht.

    – Ich werde nicht existieren Ich werde nicht existieren

    6. Mai 2016 um 1:21 Uhr

1228990cookie-checkErstellen von Bezeichnern mit universellen Zeichennamen über Token-Verkettung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy