Replacing text macros
Der Präprozessor unterstützt Text-Makroersetzung. Funktionsähnliche Text-Makroersetzung wird ebenfalls unterstützt.
Inhaltsverzeichnis |
Syntax
#define
Bezeichner Ersatzliste
(optional)
|
(1) | ||||||||
#define
Bezeichner
(
Parameter
)
Ersatzliste
(optional)
|
(2) | ||||||||
#define
Bezeichner
(
Parameter
, ...)
Ersatzliste
(optional)
|
(3) | (since C++11) | |||||||
#define
Bezeichner
(...)
Ersatzliste
(optional)
|
(4) | (since C++11) | |||||||
#undef
Bezeichner
|
(5) | ||||||||
Erklärung
#define Direktiven
Die #define Direktiven definieren den identifier als Makro, das heißt, sie weisen den Compiler an, die meisten aufeinanderfolgenden Vorkommen von identifier durch replacement-list zu ersetzen, die zusätzlich verarbeitet wird. Ausnahmen ergeben sich aus den Regeln für scanning and replacement . Wenn der identifier bereits als irgendeine Art von Makro definiert ist, ist das Programm fehlerhaft, es sei denn, die Definitionen sind identisch.
Objektartige Makros
Objektartige Makros ersetzen jedes Vorkommen des definierten identifier durch die replacement-list . Version (1) der #define -Direktive verhält sich genau so.
Funktionsartige Makros
Funktionsartige Makros ersetzen jedes Vorkommen des definierten identifier durch replacement-list , wobei zusätzlich eine Anzahl von Argumenten übernommen wird, die dann entsprechende Vorkommen der parameters in der replacement-list ersetzen.
Die Syntax eines funktionsähnlichen Makroaufrufs ähnelt der Syntax eines Funktionsaufrufs: Jedes Vorkommen des Makronamens, gefolgt von einer ( als nächstes Präprozessor-Token, leitet die Sequenz von Tokens ein, die durch die replacement-list ersetzt wird. Die Sequenz wird durch das entsprechende ) Token beendet, wobei übereinstimmende Paare von linken und rechten Klammern übersprungen werden.
Für Version (2) muss die Anzahl der Argumente gleich der Anzahl der Parameter in der Makrodefinition sein. Für Versionen (3,4) darf die Anzahl der Argumente nicht kleiner sein als die Anzahl der Parameter (
nicht
(seit C++20)
zählend
...
). Andernfalls ist das Programm fehlerhaft. Wenn der Bezeichner nicht in Funktionsschreibweise vorliegt, d.h. keine Klammern nach sich selbst hat, wird er überhaupt nicht ersetzt.
Version (2) der #define Direktive definiert ein einfaches funktionsähnliches Makro.
Version (3) der
#define
-Direktive definiert ein funktionsähnliches Makro mit variabler Anzahl von Argumenten. Die zusätzlichen Argumente (genannt
variable Argumente
) können mit dem Bezeichner
__VA_ARGS__
zugegriffen werden, der dann durch die Argumente ersetzt wird, die mit dem zu ersetzenden Bezeichner geliefert werden.
Version (4) der
#define
-Direktive definiert ein funktionsähnliches Makro mit variabler Anzahl von Argumenten, jedoch ohne reguläre Argumente. Die Argumente (genannt
variable Argumente
) können nur mit dem
__VA_ARGS__
-Bezeichner zugegriffen werden, der dann durch die Argumente ersetzt wird, die mit dem zu ersetzenden Bezeichner bereitgestellt werden.
|
Für Versionen (3,4) kann
replacement-list
die Token-Sequenz
#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) F(a, b, c) // replaced by f(0, a, b, c) F() // replaced by f(0) #define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__) G(a, b, c) // replaced by f(0, a, b, c) G(a, ) // replaced by f(0, a) G(a) // replaced by f(0, a) #define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ }) SDEF(foo); // replaced by S foo; SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 }; |
(seit C++20) |
Hinweis: Wenn ein Argument eines funktionsähnlichen Makros Kommas enthält, die nicht durch übereinstimmende Paare von linken und rechten Klammern geschützt sind (am häufigsten in Template-Argumentlisten zu finden, wie in assert ( std:: is_same_v < int , int > ) ; oder BOOST_FOREACH ( std:: pair < int , int > p, m ) ), wird das Komma als Makro-Argumenttrenner interpretiert, was zu einem Kompilierungsfehler aufgrund von nicht übereinstimmender Argumentanzahl führt.
Scannen und Ersetzen
- Das Scannen behält Makros im Auge, die sie ersetzt haben. Wenn der Scan Text findet, der einem solchen Makro entspricht, markiert er ihn als "zu ignorieren" (alle Scans werden ihn ignorieren). Dies verhindert Rekursion.
- Wenn der Scan ein funktionsähnliches Makro gefunden hat, werden Argumente gescannt, bevor sie in die replacement-list eingesetzt werden. Außer # und ## Operatoren nehmen Argumente ohne Scan.
- Nachdem ein Makro ersetzt wurde, wird der resultierende Text gescannt.
Beachten Sie, dass es möglich ist, pseudo-rekursive Makros zu definieren:
#define EMPTY #define SCAN(x) x #define EXAMPLE_() EXAMPLE #define EXAMPLE(n) EXAMPLE_ EMPTY()(n-1) (n) EXAMPLE(5) SCAN(EXAMPLE(5))
Ausgabe:
EXAMPLE_ ()(5 -1) (5) EXAMPLE_ ()(5 -1 -1) (5 -1) (5)
Reservierte Makronamen
Eine Übersetzungseinheit, die eine Standardbibliothek-Header-Datei einbindet , darf keine #define - oder #undef -Anweisungen für Namen verwenden, die in irgendeiner Standardbibliothek-Header-Datei deklariert sind.
Eine Übersetzungseinheit, die irgendeinen Teil der Standardbibliothek verwendet, darf keine Namen lexikalisch identisch zu folgenden #define oder #undef definieren:
|
(seit C++11) |
Andernfalls ist das Verhalten undefiniert.
# und ## Operatoren
In funktionsähnlichen Makros führt ein # -Operator vor einem Bezeichner in der replacement-list dazu, dass der Bezeichner durch Parameterersetzung verarbeitet und das Ergebnis in Anführungszeichen gesetzt wird, wodurch effektiv ein String-Literal erzeugt wird. Zusätzlich fügt der Präprozessor Backslashes hinzu, um die Anführungszeichen um eingebettete String-Literale zu escapen, falls vorhanden, und verdoppelt die Backslashes innerhalb des Strings nach Bedarf. Alle führenden und nachfolgenden Leerzeichen werden entfernt, und jede Abfolge von Leerzeichen in der Mitte des Textes (aber nicht innerhalb eingebetteter String-Literale) wird auf ein einzelnes Leerzeichen reduziert. Dieser Vorgang wird "Stringifizierung" genannt. Wenn das Ergebnis der Stringifizierung kein gültiges String-Literal ist, ist das Verhalten undefiniert.
|
Wenn
#
vor
#define showlist(...) puts(#__VA_ARGS__) showlist(); // expands to puts("") showlist(1, "x", int); // expands to puts("1, \"x\", int") |
(seit C++11) |
Ein
##
Operator zwischen zwei aufeinanderfolgenden Bezeichnern in der
Ersetzungsliste
führt Parameterersetzung für die beiden Bezeichner durch (die nicht zuerst makroexpandiert werden) und verkettet dann das Ergebnis. Dieser Vorgang wird "Konkatenation" oder "Token-Zusammenfügung" genannt. Nur Token, die zusammen ein gültiges Token bilden, dürfen zusammengefügt werden: Bezeichner, die einen längeren Bezeichner bilden, Ziffern, die eine Zahl bilden, oder Operatoren
+
und
=
, die ein
+=
bilden. Ein Kommentar kann nicht durch Zusammenfügen von
/
und
*
erstellt werden, da Kommentare aus dem Text entfernt werden, bevor die Makroersetzung berücksichtigt wird. Wenn das Ergebnis der Konkatenation kein gültiges Token ist, ist das Verhalten undefiniert.
Hinweis: Einige Compiler bieten eine Erweiterung, die es erlaubt, dass
##
nach einem Komma und vor
__VA_ARGS__
erscheint, wobei in diesem Fall
##
nichts bewirkt, wenn die variablen Argumente vorhanden sind, aber das Komma entfernt, wenn die variablen Argumente nicht vorhanden sind: Dies ermöglicht die Definition von Makros wie
fprintf
(
stderr
, format,
##__VA_ARGS__)
.
Dies kann auch auf standardkonforme Weise mit
__VA_OPT__
erreicht werden, wie in
fprintf
(
stderr
, format __VA_OPT__
(
,
)
__VA_ARGS__
)
.
(seit C++20)
#undef Direktive
Die #undef -Direktive hebt die Definition des Identifiers auf, das heißt, sie macht eine vorherige Definition des Identifiers durch die #define -Direktive rückgängig. Wenn der Identifier kein assoziiertes Makro besitzt, wird die Direktive ignoriert.
Vordefinierte Makros
Die folgenden Makronamen sind in jeder Übersetzungseinheit vordefiniert:
|
__cplusplus
|
kennzeichnet die Version des verwendeten C++-Standards, expandiert zum Wert
|
|
__STDC_HOSTED__
(C++11)
|
expandiert zur ganzzahligen Konstante
1
wenn die Implementierung gehostet ist (unter einem Betriebssystem läuft),
0
wenn freistehend (ohne Betriebssystem läuft)
(Makrokonstante) |
|
__FILE__
|
expandiert zum Namen der aktuellen Datei, als Zeichenkettenliteral, kann durch die
#line
-Direktive geändert werden
(Makrokonstante) |
|
__LINE__
|
expandiert zur Zeilennummer der aktuellen
physischen Quellzeile
, eine ganzzahlige Konstante, kann durch die
#line
-Direktive geändert werden
(Makrokonstante) |
|
__DATE__
|
expandiert zum Übersetzungsdatum, ein Zeichenkettenliteral der Form
"Mmm dd yyyy"
. Das erste Zeichen von
"dd"
ist ein Leerzeichen, wenn der Tag des Monats kleiner als 10 ist. Der Monatsname entspricht dem von
std::
asctime
(
)
erzeugten
(Makrokonstante) |
|
__TIME__
|
expandiert zur Übersetzungszeit, ein Zeichenkettenliteral der Form
"hh:mm:ss"
(Makrokonstante) |
|
__STDCPP_DEFAULT_NEW_ALIGNMENT__
(C++17)
|
expandiert zu einem
std::size_t
-Literal, dessen Wert die Ausrichtung ist, die durch einen Aufruf des ausrichtungsunabhängigen
operator new
garantiert wird (größere Ausrichtungen werden an die ausrichtungsabhängige Überladung wie
operator new
(
std::
size_t
,
std::
align_val_t
)
übergeben)
(Makrokonstante) |
|
__STDCPP_BFLOAT16_T__
__STDCPP_FLOAT16_T__
__STDCPP_FLOAT32_T__
__STDCPP_FLOAT64_T__
__STDCPP_FLOAT128_T__
(C++23)
|
expandiert zu
1
genau dann, wenn die Implementierung den entsprechenden
erweiterten Gleitkommatyp
unterstützt
(Makrokonstante) |
|
__STDC_EMBED_NOT_FOUND__
__STDC_EMBED_FOUND__
__STDC_EMBED_EMPTY__
(C++26)
|
expandiert zu
0
,
1
bzw.
2
(Makrokonstante) |
Die folgenden zusätzlichen Makronamen können von den Implementierungen vordefiniert werden:
|
__STDC__
|
Implementierungsdefinierter Wert, falls vorhanden, typischerweise verwendet um C-Konformität anzuzeigen
(Makrokonstante) |
||||
|
__STDC_VERSION__
(C++11)
|
Implementierungsdefinierter Wert, falls vorhanden
(Makrokonstante) |
||||
|
__STDC_ISO_10646__
(C++11)
|
(Makrokonstante) |
||||
|
__STDC_MB_MIGHT_NEQ_WC__
(C++11)
|
expandiert zu
1
falls
'x'
==
L
'x'
für ein Mitglied
x
des Basiszeichensatzes falsch sein könnte, wie z.B. auf EBCDIC-basierten Systemen die Unicode für
wchar_t
verwenden
(Makrokonstante) |
||||
|
__STDCPP_THREADS__
(C++11)
|
expandiert zu
1
falls das Programm mehr als einen Ausführungsstrang haben kann
(Makrokonstante) |
|
__STDCPP_STRICT_POINTER_SAFETY__
(C++11)
(entfernt in C++23)
|
erweitert zu
1
falls die Implementierung strikte
std::pointer_safety
unterstützt
(Makrokonstante) |
Die Werte dieser Makros (außer
__FILE__
und
__LINE__
) bleiben während der Übersetzungseinheit konstant. Versuche, diese Makros neu zu definieren oder ihre Definition aufzuheben, führen zu undefiniertem Verhalten.
Sprach-Feature-Test-MakrosDer Standard definiert einen Satz von Präprozessor-Makros, die C++-Sprachfeatures entsprechen, die in C++11 oder später eingeführt wurden. Sie sind als einfache und portable Methode zum Erkennen des Vorhandenseins dieser Features gedacht. Siehe Feature testing für Details. |
(seit C++20) |
HinweiseDie funktionslokale vordefinierte Variable __func__ ist kein vordefiniertes Makro, wird jedoch üblicherweise zusammen mit __FILE__ und __LINE__ verwendet, z.B. durch assert . |
(seit C++11) |
Beispiel
#include <iostream> // Make function factory and use it #define FUNCTION(name, a) int fun_##name() { return a; } FUNCTION(abcd, 12) FUNCTION(fff, 2) FUNCTION(qqq, 23) #undef FUNCTION #define FUNCTION 34 #define OUTPUT(a) std::cout << "output: " #a << '\n' // Using a macro in the definition of a later macro #define WORD "Hello " #define OUTER(...) WORD #__VA_ARGS__ int main() { std::cout << "abcd: " << fun_abcd() << '\n'; std::cout << "fff: " << fun_fff() << '\n'; std::cout << "qqq: " << fun_qqq() << '\n'; std::cout << FUNCTION << '\n'; OUTPUT(million); //note the lack of quotes std::cout << OUTER(World) << '\n'; std::cout << OUTER(WORD World) << '\n'; }
Ausgabe:
abcd: 12 fff: 2 qqq: 23 34 output: million Hello World Hello WORD World
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 2908 | C++98 |
es war unklar, ob
__LINE__
zur aktuellen
physischen Zeilennummer oder zur aktuellen logischen Zeilennummer expandiert |
expandiert zur aktuellen
physischen Zeilennummer |
| LWG 294 | C++98 |
eine Übersetzungseinheit, die eine Standardbibliothek-Header-Datei enthält, könnte
Makros enthalten, die Namen definieren, die in anderen Standardbibliothek-Header-Dateien deklariert sind |
verboten |
| P2621R2 | C++23 |
universelle Zeichennamen durften nicht
durch Token-Konkatenierung gebildet werden |
erlaubt |
Siehe auch
|
C++ Dokumentation
für
Makro-Symbolverzeichnis
|
|
|
C-Dokumentation
für
Ersetzen von Textmakros
|