int main()
{
i/*nt*/a = 10;
return 0;
}
Wenn ich den obigen Code habe und die Token zählen möchte, werden es 14 oder 13 Token sein?
Ist es gültig, einen Kommentar in einen Variablennamen zu schreiben? Sie können davon ausgehen, dass die int i
, int a
, int ia
sind global definiert.
Die Kommentare werden während Phase 3 der Programmübersetzung entfernt1: Jeder Kommentar wird durch ein Leerzeichen ersetzt. also der kommentar /*nt*/
ist definitiv kein Token.
Wenn keine von int
, main
, i
, a
oder return
sind als Vorverarbeitungsmakros definiert, die das Parsen des Programms erzeugt 14 Token (nicht 13):
int
main
(
)
{
i
a
=
10
;
return
0
;
}
Wenn nicht i
ist als Typ mit a definiert typedef
Anweisung, gibt es einen Syntaxfehler als i a
stimmt nicht mit einer Regel in der C-Grammatik überein.
Sie können also keine Kommentare schreiben Innerhalb Variablennamen teilt der Kommentar den Bezeichner in 2 separate Tokens. Dies gilt für alle Vorverarbeitungs- und C-Sprachtoken2.
Beachten Sie jedoch, dass Sie an ungewöhnlichen Stellen Kommentare einfügen können, z. B. zwischen unären Operatoren und ihrem Operanden oder zwischen den #
und die Vorverarbeitungsanweisung und ihre Argumente:
/**/#/**/include/**/<stdio.h>/**///////////////////////
/**/#/**/define/**/STAT/**/(/**/a/**/)/**/-/**/1/**////
/**/#/**/ifdef/**/STAT/**//////////////////////////////
/**/int/**/main/**/(/**/)/**/{/**//////////////////////
/**/int/**/a/**/=/**/+/**/1/**/;/**////////////////////
/**/printf/**/(/**/"Hello "/**/"world!\n"/**/)/**/;/**/
/**/return/**/STAT/**/;/**/////////////////////////////
/**/}/**///////////////////////////////////////////////
/**/#/**/endif/**//////////////////////////////////////
Aber die obige Makrodefinition definiert kein funktionsähnliches Makro, sondern ein reguläres Makro STAT
das erweitert sich zu ( a ) - 1
.
Variablennamen können wie jedes andere Token durch Zeilenumbrüche mit Escapezeichen geteilt werden. Escapezeichen für Zeilenumbrüche sind Sequenzen oder \
unmittelbar gefolgt von einem Zeilenumbruch. Diese Sequenzen werden während Phase 2 der Programmübersetzung aus dem Quellcode entfernt. Ihr Hauptzweck besteht darin, lange Makrodefinitionen in mehreren Zeilen zu unterbrechen.
Unten ist ein Codefragment3 das erzeugt die gleichen 14 Token:
\
i\
nt\
ma\
in()
{\
i/\
*nt\
*/a \
= 10;
r\
et\
urn\
0;}
Beachten Sie, wie der Code Colorizer die geschnittenen und gewürfelten Schlüsselwörter und Kommentare verpasst hat 🙂
1) Dieses Verhalten wurde in ANSI-C alias C89 spezifiziert. Einige alte Compiler hatten ein subtil anderes Verhalten, was zum Einfügen von Token führte, aber solche Besonderheiten sind nur von historischem Interesse.
2) Sie können fast einen Kommentar in eine String-Konstante einfügen, indem Sie sich die Tatsache zunutze machen, dass benachbarte String-Konstanten in Phase 6 der Programmübersetzung verkettet werden: printf("Hello "/* my name is Luca */"world!\n");
3) Dies Weihnachtsbaum Der Präsentationsstil ist nicht dazu gedacht, in echten Programmen verwendet zu werden, er zeigt, wie die Eingabeverarbeitungsfähigkeiten von C missbraucht werden können. Ausgefeiltere Tricks haben gewonnen Der internationale Wettbewerb für verschleierten C-Code
Aus lexikalischer Sicht ist ein Kommentar dasselbe wie ein Leerzeichen.
Abschnitt 6.4p3 des C-Standard zu lexikalischen Elementen heißt es:
… Vorverarbeitungstoken können durch getrennt werden weißer Raum; diese besteht aus Kommentaren (später beschrieben) oder Leerzeichen (Leerzeichen, horizontaler Tabulator, neue Zeile, vertikaler Tabulator und Seitenvorschub) oder beides. …
Genauer gesagt wird ein Kommentar in ein einzelnes Leerzeichen übersetzt. Dies ist in Abschnitt 5.1.1.2p3 spezifiziert:
Die Quelldatei wird in Vorverarbeitungstoken und Sequenzen von Leerzeichen (einschließlich Kommentaren) zerlegt. Eine Quelldatei darf nicht mit einem teilweisen Vorverarbeitungstoken oder einem teilweisen Kommentar enden. Jeder Kommentar wird durch ein Leerzeichen ersetzt.
Zeilenumbrüche bleiben erhalten. Ob jede nicht leere Folge von Leerzeichen außer New-Line beibehalten oder durch ein Leerzeichen ersetzt wird, ist implementierungsdefiniert.
Um dies zu veranschaulichen, wenn Sie Ihren Code durch den Präprozessor leiten, erhalten Sie Folgendes:
int main()
{
i a = 10;
return 0;
}
Kommentare dienen also wie Leerzeichen dazu, Token zu trennen.
Das bedeutet, dass der Code 14 Token enthält, nicht 13.
Das Ergebnis wird so sein, als ob Sie geschrieben hätten:
i a = 10;
NICHT:
ia = 10;
Siehe Übersetzung (auch bekannt als Kompilieren) Phase 3Schritt 2: “Jeder Kommentar wird durch ein Leerzeichen ersetzt”.
Also konzeptionell i/*nt*/a
wird i a
an diesem Punkt.
Überprüfen Sie einfach, welche Form Ihr Stück Code hat
int main()
{
int i/*nt*/a = 10;
return 0;
}
wird nach der Vorverarbeitung haben. Fügen Sie Ihrem Compiler einfach das Flag “-E” hinzu, gcc -E myscript.c und Sie erhalten das Ergebnis:
e.sharaborin@landau:~$ gcc -E myscript.c
# 1 "myscript.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "myscript.c"
int main()
{
int i a = 10;
return 0;
}
Und natürlich können Sie daraus schließen, dass ein Fehler vorliegt.
In “traditionellem” C vor ANSI, zumindest wie von implementiert GNU
cpp -traditional
würde es erweiternia = 10;
.– Nate Eldredge
27. August 2020 um 4:42 Uhr
Was für eine interessante Frage – warum ist sie mir noch nie in den Sinn gekommen?
– WestCoastProjects
27. August 2020 um 15:47 Uhr
@javadba: Weil vernünftige Leute nicht auf die Idee kommen, so etwas zu tun?
– jamesqf
27. August 2020 um 16:23 Uhr
Wenn Sie das wirklich wollen, können Sie zu Fortran wechseln. Leerzeichen außerhalb von Zeichenfolgen werden in der ersten Analysestufe entfernt.
– mpez0
27. August 2020 um 16:49 Uhr
Ich wollte gerade den Titel ändern in “…. innerhalb Variablennamen …”, aber dann wurde mir klar, dass Sie möglicherweise tatsächlich “zwischen” gemeint haben. (Ich wollte es bearbeiten, weil die Antwort auf den ursprünglichen Titel “Warum, offensichtlich!” lautet. Der wichtige Teil ist “kein Leerzeichen”.) Würde Der Titel “Trennt ein Kommentar (ohne umgebendes Leerzeichen) Tokens in C?” drückt Ihre eigentliche Frage aus?
– Peter – Setzen Sie Monica wieder ein
28. August 2020 um 7:25 Uhr