Die Implementierung von spitzen Klammern durch GCC umfasst. Warum muss es wie unten beschrieben sein?

11

Dieses Dokument in Abschnitt 2.6 Computed Includes enthält den folgenden Absatz:

Wenn die Zeile zu einem Token-Stream erweitert wird, der mit einem <Token beginnt und ein> Token enthält, werden die Token zwischen dem <und dem ersten> kombiniert, um den einzuschließenden Dateinamen zu bilden. Jedes Leerzeichen zwischen Token wird auf ein einzelnes Leerzeichen reduziert. dann wird jedes Leerzeichen nach dem Anfangsbuchstaben <beibehalten, ein nachfolgendes Leerzeichen vor dem Schließen> wird jedoch ignoriert . CPP sucht nach der Datei gemäß den Regeln für Winkelklammern.

Ich weiß, dass dies eine definierte Implementierung ist, aber warum muss dies für GCC so sein? Ich beziehe mich speziell auf den hervorgehobenen Satz oben.

BEARBEITEN

Ich habe gerade bemerkt, dass der dritte Absatz vor dem oben zitierten Folgendes besagt:

Sie müssen vorsichtig sein, wenn Sie das Makro definieren. #definespeichert Token, keinen Text. Der Präprozessor kann nicht wissen, dass das Makro als Argument für verwendet wird #include, und generiert daher normale Token, keinen Headernamen. Es ist unwahrscheinlich, dass dies zu Problemen führt, wenn Sie doppelte Anführungszeichen verwenden, die nahe genug an Zeichenfolgenkonstanten liegen. Wenn Sie jedoch spitze Klammern verwenden, können Probleme auftreten .

Weiß jemand, auf welche Probleme hier hingewiesen wird?

Ayrosa
quelle
6
Die Entwickler von GCC halten die Leerzeichen am Ende eines Dateinamens für einen Gräuel.
user3386109
1
Dateinamen mit führenden und / oder nachfolgenden Leerzeichen sind besonders unter Windows sehr schwierig zu bearbeiten.
Remy Lebeau
1
Nur weil es so definiert wurde, heißt das nicht unbedingt, dass es so definiert werden muss. Es ist nicht durch den Standard vorgeschrieben.
Eerorika
Visual Studio entfernt sowohl den Anfangs- als auch den Endspeicherplatz und verhält sich daher unterschiedlich. HP aCC verhält sich wie gcc (möglicherweise aus Kompatibilitätsgründen).
Slimak
Manchmal beschreibt die Dokumentation einfach, was der Code tut, und nicht umgekehrt, insbesondere in Fällen, die keine Rolle spielen (Sie können überall Leerzeichen verwenden, wenn Sie doppelte Anführungszeichen verwenden).
Rustyx

Antworten:

8

Ich denke, der Implementierer hat den einfachsten Weg gewählt, als er diese Funktionalität implementiert hat, ohne viel darüber nachzudenken.

Es scheint, dass die erste Implementierung am 03.07.2000 (vor zwei Jahrzehnten!) Gelandet ist. Der relevante Teil sieht aus wie ( Quelle ):

  for (;;)
    {
      t = cpp_get_token (pfile);
      if (t->type == CPP_GREATER || t->type == CPP_EOF)
        break;

      CPP_RESERVE (pfile, TOKEN_LEN (t));
      if (t->flags & PREV_WHITE)
        CPP_PUTC_Q (pfile, ' ');
      pfile->limit = spell_token (pfile, t, pfile->limit);
    }

Insbesondere bricht es aus, wenn es das CPP_GREATERToken (dh >) sieht , bevor Speicher für das Token reserviert wird. Dies ist sinnvoll, da kein Speicher zugewiesen werden muss, wenn das Token nicht in den Puffer geschrieben wird.

Erst nachdem der Speicher reserviert wurde, prüft der Präprozessor, ob dem Token ein Leerzeichen ( t->flags & PREV_WHITE) vorangestellt ist, und schreibt dann ein Leerzeichen in den Puffer.

Infolgedessen werden in < foo / bar >nur die Leerzeichen vor foo( dh nach dem Anfangsbuchstaben <) /und barbeibehalten.

cpplearner
quelle
Geniale, großartige Antwort. Dies ist das erste Mal, dass ich die Möglichkeit habe, einen Code in GCC zu sehen. Danke dafür.
Ayrosa
Aber ist es nicht so, dass die Bedingung dem if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');widerspricht, was in dem Dokument gesagt wird: "Jedes Leerzeichen zwischen Token wird auf ein einzelnes Leerzeichen reduziert; ..."?
Ayrosa