Namespaces
Variants

Replacing text macros

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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 __VA_OPT__( content  ) enthalten, die durch content ersetzt wird, falls __VA_ARGS__ nicht leer ist, und andernfalls zu nichts expandiert.

#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 __VA_ARGS__ erscheint, wird das gesamte expandierte __VA_ARGS__ in Anführungszeichen gesetzt:

#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
  • 199711L (bis C++11) ,
  • 201103L (C++11) ,
  • 201402L (C++14) ,
  • 201703L (C++17) ,
  • 202002L (C++20) , oder
  • 202302L (C++23)
    (Makrokonstante)
__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)

expandiert zu einer Integer-Konstante der Form yyyymmL , falls wchar_t Unicode verwendet, gibt das Datum die neueste unterstützte Unicode-Revision an

(bis C++23)

Implementierungsdefinierter Wert, falls vorhanden

(seit C++23)

(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-Makros

Der 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)


Hinweise

Die 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