Namensräume
Varianten
Aktionen

Übersetzungsphasen

Von cppreference.com
< c‎ | Sprache

Die C-Quelldatei wird vom Compiler so verarbeitet, als ob die folgenden Phasen in exakt dieser Reihenfolge ablaufen. Die tatsächliche Implementierung kann diese Aktionen kombinieren oder sie unterschiedlich verarbeiten, solange das Verhalten dasselbe ist.

Inhalt

[bearbeiten] Phase 1

1) Die einzelnen Bytes der Quelldatei (die im Allgemeinen eine Textdatei in einer Multibyte-Kodierung wie UTF-8 ist) werden auf eine implementierungsabhängige Weise auf die Zeichen des Quellzeichensatzes abgebildet. Insbesondere werden betriebssystemabhängige Zeilenende-Indikatoren durch Zeilenumbruchzeichen ersetzt.
Der Quellzeichensatz ist ein Multibyte-Zeichensatz, der den grundlegenden Quellzeichensatz als Single-Byte-Teilmenge enthält, bestehend aus den folgenden 96 Zeichen
a) 5 Leerzeichen (Leerzeichen, horizontaler Tabulator, vertikaler Tabulator, Seitenvorschub, Zeilenvorschub)
b) 10 Ziffern von '0' bis '9'
c) 52 Buchstaben von 'a' bis 'z' und von 'A' bis 'Z'
d) 29 Satzzeichen: _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
2) Trigraphensequenzen werden durch entsprechende Einzeichen-Darstellungen ersetzt.(bis C23)

[bearbeiten] Phase 2

1) Wann immer ein Backslash am Ende einer Zeile erscheint (unmittelbar gefolgt vom Zeilenumbruchzeichen), werden sowohl Backslash als auch Zeilenumbruch gelöscht, wodurch zwei physische Quellzeilen zu einer logischen Quellzeile zusammengefasst werden. Dies ist eine Einmal-Operation: Eine Zeile, die mit zwei Backslashes endet, gefolgt von einer leeren Zeile, fasst nicht drei Zeilen zu einer zusammen.
#include <stdio.h>
 
#define PUTS p\
u\
t\
s
/* Line splicing is in phase 2 while macros
 * are tokenized in phase 3 and expanded in phase 4,
 * so the above is equivalent to #define PUTS puts
 */
 
int main(void)
{
 /* Use line splicing to call puts */ PUT\
S\
("Output ends here\\
0Not printed" /* After line splicing, the remaining backslash
               * escapes the 0, ending the string early.
               */
);
}
2) Wenn eine nicht-leere Quelldatei nach diesem Schritt nicht mit einem Zeilenumbruchzeichen endet (entweder weil sie ursprünglich keinen hatte oder weil sie mit einem Backslash endete), ist das Verhalten undefiniert.

[bearbeiten] Phase 3

1) Die Quelldatei wird in Kommentare, Folgen von Leerzeichen (Leerzeichen, horizontaler Tabulator, Zeilenvorschub, vertikaler Tabulator und Seitenvorschub) und Präprozessor-Tokens zerlegt, die folgende sind
a) Header-Namen: <stdio.h> oder "myfile.h"
c) Präprozessor-Zahlen, die Ganzzahlkonstanten und Gleitkommakonstanten umfassen, aber auch einige ungültige Tokens wie 1..E+3.foo oder 0JBK
e) Operatoren und Satzzeichen, wie +, <<=, <% oder ##.
f) einzelne Nicht-Leerzeichen, die in keine andere Kategorie passen
2) Jeder Kommentar wird durch ein Leerzeichen ersetzt
3) Zeilenumbrüche werden beibehalten, und es ist implementierungsabhängig, ob Nicht-Zeilenumbruch-Leerzeichenfolgen zu einzelnen Leerzeichen reduziert werden dürfen.

Wenn die Eingabe bis zu einem bestimmten Zeichen in Präprozessor-Tokens zerlegt wurde, wird das nächste Präprozessor-Token im Allgemeinen als die längste Zeichenfolge genommen, die ein Präprozessor-Token bilden könnte, selbst wenn dies zu einem späteren Analysefehler führen würde. Dies ist allgemein als maximaler Fraß (maximal munch) bekannt.

int foo = 1;
// int bar = 0xE+foo; // error: invalid preprocessing number 0xE+foo
int bar = 0xE/*Comment expands to a space*/+foo; // OK: 0xE + foo
int baz = 0xE + foo; // OK: 0xE + foo
int pub = bar+++baz; // OK: bar++ + baz
int ham = bar++-++baz; // OK: bar++ - ++baz
// int qux = bar+++++baz; // error: bar++ ++ +baz, not bar++ + ++baz
int qux = bar+++/*Saving comment*/++baz; // OK: bar++ + ++baz

Die einzige Ausnahme von der maximalen Fraß-Regel ist

  • Header-Name-Präprozessor-Tokens werden nur innerhalb einer #include-Direktive oder #embed(seit C23), in __has_include und __has_embed-Ausdrücken(seit C23) und an implementierungsabhängigen Stellen innerhalb einer #pragma-Direktive gebildet.
#define MACRO_1 1
#define MACRO_2 2
#define MACRO_3 3
#define MACRO_EXPR (MACRO_1 <MACRO_2> MACRO_3) // OK: <MACRO_2> is not a header-name

[bearbeiten] Phase 4

1) Der Präprozessor wird ausgeführt.
2) Jede Datei, die mit der #include-Direktive eingeführt wird, durchläuft rekursiv die Phasen 1 bis 4.
3) Am Ende dieser Phase werden alle Präprozessor-Direktiven aus der Quelle entfernt.

[bearbeiten] Phase 5

1) Alle Zeichen und Escape-Sequenzen in Zeichenkonstanten und Zeichenkettenliteralen werden vom Quellzeichensatz in den Ausführungszeichensatz konvertiert (welcher ein Multibyte-Zeichensatz wie UTF-8 sein kann, solange alle 96 Zeichen aus dem in Phase 1 aufgeführten grundlegenden Quellzeichensatz eine Ein-Byte-Darstellung haben). Wenn das durch eine Escape-Sequenz spezifizierte Zeichen kein Mitglied des Ausführungszeichensatzes ist, ist das Ergebnis implementierungsabhängig, wird aber garantiert kein Null- (Wide-)Zeichen sein.

Hinweis: Die in dieser Phase durchgeführte Konvertierung kann in einigen Implementierungen durch Befehlszeilenoptionen gesteuert werden: gcc und clang verwenden -finput-charset zur Angabe der Kodierung des Quellzeichensatzes, -fexec-charset und -fwide-exec-charset zur Angabe der Kodierungen des Ausführungszeichensatzes in den Zeichenkettenliteralen und Zeichenkonstanten, die kein Kodierungspräfix haben(seit C11).

[bearbeiten] Phase 6

Benachbarte Zeichenkettenliterale werden verkettet.

[bearbeiten] Phase 7

Die Kompilierung findet statt: Die Tokens werden syntaktisch und semantisch analysiert und als eine Translationseinheit übersetzt.

[bearbeiten] Phase 8

Das Linken findet statt: Translationseinheiten und Bibliothekskomponenten, die zur Erfüllung externer Referenzen benötigt werden, werden zu einem Programmabbild gesammelt, das Informationen für die Ausführung in seiner Ausführungsumgebung (dem Betriebssystem) enthält.

[bearbeiten] Referenzen

  • C23-Standard (ISO/IEC 9899:2024)
  • 5.1.1.2 Übersetzungsphasen (p: TBD)
  • 5.2.1 Zeichensätze (p: TBD)
  • 6.4 Lexikalische Elemente (p: TBD)
  • C17-Standard (ISO/IEC 9899:2018)
  • 5.1.1.2 Übersetzungsphasen (p: 9-10)
  • 5.2.1 Zeichensätze (p: 17)
  • 6.4 Lexikalische Elemente (p: 41-54)
  • C11-Standard (ISO/IEC 9899:2011)
  • 5.1.1.2 Übersetzungsphasen (p: 10-11)
  • 5.2.1 Zeichensätze (p: 22-24)
  • 6.4 Lexikalische Elemente (p: 57-75)
  • C99-Standard (ISO/IEC 9899:1999)
  • 5.1.1.2 Übersetzungsphasen (p: 9-10)
  • 5.2.1 Zeichensätze (p: 17-19)
  • 6.4 Lexikalische Elemente (p: 49-66)
  • C89/C90-Standard (ISO/IEC 9899:1990)
  • 2.1.1.2 Übersetzungsphasen
  • 2.2.1 Zeichensätze
  • 3.1 Lexikalische Elemente

[bearbeiten] Siehe auch

C++ Dokumentation für Übersetzungsphasen