Namensräume
Varianten
Aktionen

Textmakros ersetzen

Von cppreference.com
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Der Präprozessor unterstützt das Ersetzen von Textmakros. Funktionsähnliche Textmakros werden ebenfalls unterstützt.

Inhalt

[bearbeiten] Syntax

#define identifikator ersetzungsliste (optional) (1)
#define identifikator (parameter ) ersetzungsliste (optional) (2)
#define identifikator (parameter , ...) ersetzungsliste (optional) (3) (seit C++11)
#define identifikator (...) ersetzungsliste (optional) (4) (seit C++11)
#undef identifikator (5)

[bearbeiten] Erklärung

[bearbeiten] #define-Direktiven

Die #define-Direktiven definieren den identifikator als Makro, d. h. sie weisen den Compiler an, die meisten aufeinanderfolgenden Vorkommen von identifikator durch ersetzungsliste zu ersetzen, die zusätzlich verarbeitet wird. Ausnahmen ergeben sich aus den Regeln des Scannens und Ersetzens. Wenn der Bezeichner bereits als irgendeine Art von Makro definiert ist, ist das Programm schlecht formuliert, es sei denn, die Definitionen sind identisch.

[bearbeiten] Objektähnliche Makros

Objektähnliche Makros ersetzen jedes Vorkommen eines definierten identifikator durch eine ersetzungsliste. Version (1) der #define-Direktive verhält sich genau so.

[bearbeiten] Funktionsähnliche Makros

Funktionsähnliche Makros ersetzen jedes Vorkommen eines definierten identifikator durch eine ersetzungsliste, wobei zusätzlich eine Anzahl von Argumenten angenommen wird, die dann entsprechende Vorkommen von Parametern in der ersetzungsliste ersetzen.

Die Syntax eines funktionsähnlichen Makroaufrufs ähnelt der Syntax eines Funktionsaufrufs: Jede Instanz des Makronamens, gefolgt von einer ( als nächstes Präprozessor-Token, leitet die zu ersetzende Token-Sequenz durch die ersetzungsliste ein. Die Sequenz wird durch das passende )-Token beendet, wobei dazwischenliegende übereinstimmende Klammerpaare übersprungen werden.

Bei Version (2) muss die Anzahl der Argumente mit der Anzahl der Parameter in der Makrodefinition übereinstimmen. Bei den Versionen (3, 4) darf die Anzahl der Argumente nicht kleiner sein als die Anzahl der Parameter (wobei ... nicht mitgezählt wird nicht(seit C++20)). Andernfalls ist das Programm schlecht formuliert. Wenn der Bezeichner nicht in funktioneller Notation steht, d. h. keine Klammern hinter sich 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 Argumentanzahl. Die zusätzlichen Argumente (sogenannte _variable Argumente_) können über den Bezeichner __VA_ARGS__ abgerufen werden, der dann mit den Argumenten ersetzt wird, die dem zu ersetzenden Bezeichner zugeordnet sind.

Version (4) der #define-Direktive definiert ein funktionsähnliches Makro mit variabler Argumentanzahl, aber ohne reguläre Argumente. Die Argumente (sogenannte _variable Argumente_) können nur über den Bezeichner __VA_ARGS__ abgerufen werden, der dann mit den Argumenten ersetzt wird, die dem zu ersetzenden Bezeichner zugeordnet sind.

Bei den Versionen (3, 4) kann die ersetzungsliste die Token-Sequenz __VA_OPT__(inhalt ) enthalten, die durch inhalt ersetzt wird, wenn __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 von übereinstimmenden Klammerpaaren geschützt sind (am häufigsten in Vorlagen-Argumentlisten, wie in assert(std::is_same_v<int, int>); oder BOOST_FOREACH(std::pair<int, int> p, m) gefunden), wird das Komma als Trennzeichen für Makroargumente interpretiert, was zu einem Kompilierungsfehler aufgrund eines falschen Argumentzählers führt.

[bearbeiten] Scannen und Ersetzen
  • Beim Scannen wird verfolgt, welche Makros sie ersetzt haben. Wenn beim Scannen Text gefunden wird, der einem solchen Makro entspricht, wird er als "zu ignorieren" markiert (alle Scans werden ihn ignorieren). Dies verhindert Rekursion.
  • Wenn beim Scannen ein funktionsähnliches Makro gefunden wird, werden die Argumente gescannt, bevor sie in die ersetzungsliste eingefügt werden. Ausgenommen sind die #- und ##-Operatoren, die ein Argument ohne Scan übernehmen.
  • Nachdem das Makro ersetzt wurde, wird der Ergebnis-Text gescannt.

Hinweis: Es ist möglich, ein pseudo-rekursives Makro 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)

[bearbeiten] Reservierte Makronamen

Eine Übersetzungseinheit, die eine Standardbibliotheks-Headerdatei einbindet, darf keine Namen definieren oder undefinieren, die in irgendeiner Standardbibliotheks-Headerdatei deklariert sind.

Einer Übersetzungseinheit, die Teile der Standardbibliothek verwendet, ist es nicht gestattet, Namen zu definieren oder zu undefinieren, die lexikalisch identisch sind mit:

(seit C++11)

Andernfalls ist das Verhalten undefiniert.

[bearbeiten] #- und ##-Operatoren

In funktionsähnlichen Makros wandelt ein #-Operator vor einem Bezeichner in der ersetzungsliste den Bezeichner durch Parameterersetzung um und schließt das Ergebnis in Anführungszeichen ein, wodurch effektiv ein Zeichenkettenliteral entsteht. Darüber hinaus fügt der Präprozessor Backslashes hinzu, um die Anführungszeichen um eingebettete Zeichenkettenliterale zu maskieren, falls vorhanden, und verdoppelt die Backslashes innerhalb der Zeichenkette nach Bedarf. Alle führenden und nachfolgenden Leerzeichen werden entfernt, und jede Leerzeichensequenz in der Mitte des Textes (aber nicht innerhalb eingebetteter Zeichenkettenliterale) wird zu einem einzelnen Leerzeichen zusammengefasst. Diese Operation wird als "Stringifizierung" bezeichnet. Wenn das Ergebnis der Stringifizierung kein gültiges Zeichenkettenliteral ist, ist das Verhalten undefiniert.

Wenn # vor __VA_ARGS__ erscheint, wird der gesamte expandierte __VA_ARGS__ in Anführungszeichen eingeschlossen

#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 eine Parameterersetzung für die beiden Bezeichner durch (die nicht zuerst als Makros expandiert werden) und verkettet dann das Ergebnis. Diese Operation wird als "Verkettung" oder "Token-Pasten" bezeichnet. Nur Token, die zusammen ein gültiges Token bilden, können 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 das Zusammenfügen von / und * erstellt werden, da Kommentare vor der Makrosubstitution aus dem Text entfernt werden. Wenn das Ergebnis der Verkettung kein gültiges Token ist, ist das Verhalten undefiniert.

Hinweis: Einige Compiler bieten eine Erweiterung, die es ermöglicht, dass ## nach einem Komma und vor __VA_ARGS__ erscheint. In diesem Fall bewirkt der ## nichts, wenn die variablen Argumente vorhanden sind, entfernt aber das Komma, wenn die variablen Argumente nicht vorhanden sind: Dies ermöglicht die Definition von Makros wie fprintf (stderr, format, ##__VA_ARGS__). Dies kann auch auf standardmäßige Weise mit __VA_OPT__ erreicht werden, z. B. fprintf (stderr, format __VA_OPT__(, ) __VA_ARGS__).(seit C++20)

[bearbeiten] #undef-Direktive

Die #undef-Direktive hebt die Definition des identifikator auf, d. h. sie macht eine vorherige Definition des identifikator durch eine #define-Direktive rückgängig. Wenn der Bezeichner kein zugeordnetes Makro hat, wird die Direktive ignoriert.

[bearbeiten] Vordefinierte Makros

Die folgenden Makronamen sind in jeder Übersetzungseinheit vordefiniert:

__cplusplus
bezeichnet die Version des verwendeten C++-Standards und expandiert zum Wert
  • 199711L(bis C++11),
  • 201103L(C++11),
  • 201402L(C++14),
  • 201703L(C++17),
  • 202002L(C++20) oder
  • 202302L(C++23)
    (Makro-Konstante)
__STDC_HOSTED__
(C++11)
expandiert zur Ganzzahlkonstante 1, wenn die Implementierung gehostet wird (unter einem Betriebssystem läuft), 0 wenn sie eigenständig ist (ohne Betriebssystem läuft)
(Makro-Konstante)
__FILE__
expandiert zum Namen der aktuellen Datei als Zeichenkettenliteral, kann durch die #line-Direktive geändert werden
(Makro-Konstante)
__LINE__
expandiert zur Zeilennummer der aktuellen physischen Quellzeile, einer Ganzzahlkonstante, kann durch die #line-Direktive geändert werden
(Makro-Konstante)
__DATE__
expandiert zum Übersetzungsdatum, einem 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 ist derselbe wie von std::asctime() generiert.
(Makro-Konstante)
__TIME__
expandiert zur Übersetzungszeit, einem Zeichenkettenliteral der Form "hh:mm:ss"
(Makro-Konstante)
__STDCPP_DEFAULT_NEW_ALIGNMENT__
(C++17)
expandiert zu einem std::size_t-Literal, dessen Wert die Ausrichtung ist, die von einem Aufruf eines Alignment-unaware operator new garantiert wird (größere Ausrichtungen werden an die Alignment-aware Überladung übergeben, z. B. operator new(std::size_t, std::align_val_t))
(Makro-Konstante)
__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 die entsprechenden erweiterten Gleitkommatypen unterstützt
(Makro-Konstante)

Die folgenden zusätzlichen Makronamen können von den Implementierungen vordefiniert werden:

__STDC__
implementierungsdefinierter Wert, falls vorhanden, normalerweise zur Anzeige der C-Konformität verwendet
(Makro-Konstante)
__STDC_VERSION__
(C++11)
implementierungsdefinierter Wert, falls vorhanden
(Makro-Konstante)
__STDC_ISO_10646__
(C++11)

expandiert zu einer Ganzzahlkonstante der Form yyyymmL; wenn wchar_t Unicode verwendet, gibt das Datum die neueste unterstützte Unicode-Revision an

(bis C++23)

implementierungsdefinierter Wert, falls vorhanden

(seit C++23)

(Makro-Konstante)
__STDC_MB_MIGHT_NEQ_WC__
(C++11)
expandiert zu 1, wenn 'x' == L'x' für ein Mitglied der Basistextmenge falsch sein könnte, z. B. auf EBCDIC-basierten Systemen, die Unicode für wchar_t verwenden
(Makro-Konstante)
__STDCPP_THREADS__
(C++11)
expandiert zu 1, wenn das Programm mehr als einen Ausführungsfaden haben kann
(Makro-Konstante)
__STDCPP_STRICT_POINTER_SAFETY__
(C++11)(entfernt in C++23)
expandiert zu 1, wenn die Implementierung strenge std::pointer_safety aufweist
(Makro-Konstante)

Die Werte dieser Makros (mit Ausnahme von __FILE__ und __LINE__) bleiben während der gesamten Übersetzungseinheit konstant. Versuche, diese Makros neu zu definieren oder zu undefinieren, führen zu undefiniertem Verhalten.

Sprachmerkmal-Testmakros

Der Standard definiert eine Reihe von Präprozessor-Makros, die den in C++11 oder später eingeführten C++-Sprachmerkmalen entsprechen. Sie sind als einfache und portable Methode gedacht, um die Anwesenheit dieser Merkmale zu erkennen.

Siehe Merkmalstests für Details.

(seit C++20)


Anmerkungen

Die funktionslokale vordefinierte Variable __func__ ist kein vordefiniertes Makro, wird aber normalerweise zusammen mit __FILE__ und __LINE__ verwendet, z. B. von assert.

(seit C++11)

[bearbeiten] 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

[bearbeiten] Defect Reports

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 2908 C++98 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 Standardbibliotheks-Headerdatei einbindet, könnte
Makros enthalten, die Namen definieren, die in anderen Standardbibliotheks-Headerdateien deklariert sind
verboten
P2621R2 C++23 universelle Zeichencodes konnten nicht
durch Token-Verkettung gebildet werden
erlaubt

[bearbeiten] Siehe auch

C++ Dokumentation für Makro-Symbolindex
C-Dokumentation für Textmakros ersetzen