Ist es möglich, eine andere Präprozessordirektive zu definieren?

Lesezeit: 5 Minuten

Benutzer-Avatar
ST3

Ich habe durchgesehen Code-Golf und kam auf die Idee, diesen Code auszuprobieren:

#define D #define Nachdem ich diese Zeile hinzugefügt hatte, funktionierte alles einwandfrei, aber ich habe sie folgendermaßen erweitert:

#define D #define
D VALUE

Und hier habe ich 5 Kompilierungsfehler bekommen. Wenn ich mich verändere D hinein #define alles ist in Ordnung, kann jemand erklären, warum dieser Code illegal ist?

HINWEIS: Ich habe den VS2008-Compiler verwendet.

BEARBEITEN: Nach einigen Antworten sehe ich, dass ich eine Fehlerliste für die Kompilierung geben musste:

  1. Fehler C2121: ‘#’ : ungültiges Zeichen : möglicherweise das Ergebnis einer Makroerweiterung
  2. Fehler C2146: Syntaxfehler: fehlendes ‘;’ vor Kennung ‘VALUE’
  3. Fehler C4430: fehlender Typbezeichner – Int angenommen. Hinweis: C++ unterstützt default-int nicht
  4. Fehler C2144: Syntaxfehler: „void“ sollte „;“ vorangestellt werden
  5. Fehler C4430: fehlender Typbezeichner – Int angenommen. Hinweis: C++ unterstützt default-int nicht

Der erste Fehler zeigt das D ist nicht nur define sondern beinhaltet auch #.

  • Da es implementierungsabhängig sein kann, geben Sie bitte an, welchen Compiler Sie verwenden.

    – Julio Franco

    27. August 2013 um 20:18 Uhr

  • “Warum ist dieser Code illegal?” – Weil Sie Präprozessordirektiven nicht neu definieren können.

    Benutzer529758

    27. August 2013 um 20:18 Uhr

  • @H2CO3 Ich konnte es neu definieren, weil es beim ersten Mal funktionierte, aber nach der Verwendung dieser Definition bekam ich einen Kompilierungsfehler.

    – ST3

    27. August 2013 um 20:20 Uhr

  • @ user2623967 Der C-Präprozessor definiert keine Metasyntax.

    Benutzer529758

    27. August 2013 um 20:24 Uhr

  • @ user2623967: Nein, du konntest es nicht neu definieren. Solange Sie kein Präprozessormakro verwenden, wird es nicht erweitert und daher nicht überprüft. In diesem speziellen Fall macht die Erweiterung nicht das, was Sie denken.

    – yzt

    27. August 2013 um 20:25 Uhr

Benutzer-Avatar
Eric Postpischil

C 2011 (N1570) 6.10.3.4 3: „Die resultierende vollständig durch Makros ersetzte Vorverarbeitungstokensequenz wird nicht als Vorverarbeitungsanweisung verarbeitet, selbst wenn sie einer solchen ähnelt, …“

C++ 2010 (N3092) 16.3.4 [cpp.rescan] 3 hat genau den gleichen Text.

  • Dies ist die richtige Antwort. Der C-Sprachstandard spezifiziert die genaue Reihenfolge der Operationen bei der Übersetzung des Programmquellcodes.

    – Adam Rosenfield

    27. August 2013 um 20:33 Uhr

  • Dieser „auch wenn er einem ähnelt“-Text geht zurück auf den ANSI-C-Standard von 1989 (und höchstwahrscheinlich Entwürfe davor).

    – Kas

    28. August 2013 um 3:19 Uhr

  • N3092 ist kein Standard… obwohl der Text in C++98, C++11 und jedem C++-Standardentwurf, der jemals war oder jemals sein wird, zweifellos derselbe ist.

    – Kartoffelklatsche

    28. August 2013 um 3:39 Uhr

Dieser Code ist illegal, weil die Sprachspezifikation besagt, dass er illegal ist. Gemäß der C- und C++-Präprozessorspezifikation wird jeder Code, den Sie mit dem Präprozessor erstellen, niemals als eine weitere Präprozessordirektive interpretiert. Kurz gesagt, Sie können Präprozessordirektiven nicht mit Präprozessor erstellen. Zeitraum.

(Außerdem können Sie keine Kommentare mit dem Präprozessor erstellen.)

Benutzer-Avatar
Karl Norum

Es sieht so aus, als würde Ihr Präprozessor die gewünschte Ersetzung vornehmen, aber Sie würden wahrscheinlich nicht das gewünschte Verhalten erhalten – der Präprozessor ist normalerweise nur eine Operation in einem Durchgang. Beispiel (mit Clang, aber Sie sollten in der Lage sein, mit den entsprechenden VS2008-Flags zu reproduzieren):

$ cat example.c 
#define D #define
D VALUE
$ cc -P -E example.c 

 #define VALUE

Dass #define VALUE geht direkt zum Compiler, der nichts damit anzufangen weiß – schließlich ist es eine Präprozessordirektive. Der Fehler von Clang ähnelt Ihrem als Referenz:

$ cc -c example.c 
example.c:2:1: error: expected identifier or '('
D VALUE
^
example.c:1:11: note: expanded from macro 'D'
#define D #define
          ^
1 error generated.

  • Ob der Präprozessor eine Single-Pass-Operation ist oder nicht, ist irrelevant. Der Präprozessor müsste die Datei nicht mehr als einmal scannen, um einzelne Zeilen erneut zu verarbeiten. es könnte lediglich jede Zeile so oft wie nötig verarbeiten. Tatsächlich tut es Folgendes: Die Makroersetzung wird wiederholt durchgeführt. Der Grund, warum Präprozessordirektiven nach der Makroersetzung nicht verarbeitet werden, liegt darin, dass der Sprachstandard dies nicht vorschreibt.

    – Eric Postpischil

    27. August 2013 um 20:33 Uhr

  • Ja, einverstanden. Ich kannte die offiziellen Regeln nicht.

    – Karl Norum

    27. August 2013 um 20:43 Uhr

Benutzer-Avatar
LarryPel

Das wird nicht funktionieren, da die Vorverarbeitung in einem einzigen Durchgang durchgeführt wird. Betrachten Sie zum Beispiel den nächsten Code:

#define MYDEFINEWEIRD #define

MYDEFINEWEIRD N 6

int main() {

  return 0;
}

Nach der Vorverarbeitung sieht Ihr Code so aus:

 #define N 6
int main() {

  return 0;
}

und “#define” ist keine gültige Syntax in C oder C++. Da die resultierende Präprozessordirektive nicht verarbeitet wird, löst sie auch keine nachfolgenden Verweise auf das Makro “N” in Ihrem Code auf.

Nur zum Spaß können Sie den Präprozessor zweimal von der Befehlszeile aus mit g++/gcc aufrufen. Betrachten Sie den nächsten Code (define.cpp):

#include <iostream>

#define MYDEFINEWEIRD #define
MYDEFINEWEIRD N 6

using namespace std;

int main() {
  cout << N << endl;
  return 0;
}

Dann können Sie Folgendes tun:

$ g++ -E define.cpp | g++ -o define -x c++ - && ./define

und wird ausgeben:

6

Codezeilen in den Augen des Präprozessors sind entweder Präprozessoranweisungen (und haben daher keine Ersetzungen an ihnen) oder normale Textanweisungen (und haben Ersetzungen vorgenommen). Eins kann nicht beides sein, also wird nach dem Ersetzen von ‘D’ nur noch nachgeschaut, ob noch weitere Makros zu ersetzen sind. Da es keine gibt, lässt es einfach ‘#define’ im C++-Code unverändert und der C++-Compiler gibt einen Fehler aus, wenn er es sieht (da ‘#define’ kein gültiger C++-Code ist).

Also zeigen Sie meinen Punkt mehr, das ist ungültiger Code für den Präprozessor:

#define D define
#D value

Weil der Präprozessor bei Präprozessoranweisungen keine Makroersetzung durchführt und “#D” kein erkannter Präprozessorbefehl ist. Und das:

#define D #define
D value

Ergebnisse in diesem C++-Code:

#define value

Was ungültig ist, da der Präprozessor bereits ausgeführt wird.

Benutzer-Avatar
Dietmar Kühl

Betrachten Sie die Grammatik in 16 [cpp] Absatz 1, a Ersatzliste besteht aus PP-Token was die Produktion beinhalten kann # keine Direktive die in Absatz 2 des gleichen Absatzes wie beschrieben ist

Eine Nicht-Direktive darf nicht mit einem der Direktivennamen beginnen, die in der Liste erscheinen.

Das heißt, etwas von der Form

#define NAME # define

zufällig illegal! Beachten Sie auch, dass die # in diesem Zusammenhang tut nicht Verwandle das nächste Wort in einen String: das Zitat nach a # passiert nur shen die # unmittelbar gefolgt von einem Makroparameternamen in einem Makro im Funktionsstil.

1257420cookie-checkIst es möglich, eine andere Präprozessordirektive zu definieren?

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

Privacy policy