Namespaces
Variants

Replacing text macros

From cppreference.net

Der Präprozessor unterstützt Text-Makroersetzung und funktionsähnliche Text-Makroersetzung.

Inhaltsverzeichnis

Syntax

#define identifier replacement-list  (optional) (1)
#define identifier  ( parameters ) replacement-list (2)
#define identifier  ( parameters , ... ) replacement-list (3) (seit C99)
#define identifier  ( ... ) replacement-list (4) (seit C99)
#undef identifier (5)

Erklärung

#define Direktiven

Die #define Direktiven definieren den identifier als ein Macro, das heißt sie weisen den Compiler an, alle nachfolgenden Vorkommen von identifier durch replacement-list zu ersetzen, was optional zusätzlich verarbeitet werden kann. Wenn der identifier bereits als irgendeine Art von Macro definiert ist, ist das Programm fehlerhaft, es sei denn die Definitionen sind identisch.

Objektartige Makros

Objektartige Makros ersetzen jedes Vorkommen eines definierten identifier durch replacement-list . Version (1) der #define -Direktive verhält sich genau so.

Funktionsartige Makros

Funktionsartige Makros ersetzen jedes Vorkommen eines 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 Ersetzungsliste ersetzt wird. Die Sequenz wird durch das entsprechende ) Token beendet, wobei dazwischenliegende passende Paare von linken und rechten Klammern übersprungen werden.

Die Anzahl der Argumente muss mit der Anzahl der Argumente in der Makrodefinition ( parameters ) übereinstimmen, andernfalls ist das Programm fehlerhaft. Wenn der Bezeichner nicht in Funktionsschreibweise vorliegt, d.h. keine Klammern nach sich hat, wird er überhaupt nicht ersetzt.

Version (2) der #define -Direktive definiert ein einfaches funktionsähnliches Makro.

Version (3) der #define Direktive definiert einen funktionsähnlichen Makro mit variabler Anzahl an Argumenten. Die zusätzlichen Argumente können mittels des __VA_ARGS__ Identifikators zugänglich gemacht werden, welcher anschließend durch die Argumente ersetzt wird, die mit dem zu ersetzenden Identifikator bereitgestellt werden.

Version (4) der #define Direktive definiert ein funktionsähnliches Makro mit variabler Anzahl an Argumenten, jedoch ohne reguläre Argumente. Die 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 C23)


Hinweis: Wenn ein Argument eines funktionsähnlichen Makros Kommas enthält, die nicht durch passende Paare von linken und rechten Klammern geschützt sind (wie z.B. macro ( array [ x = y, x + 1 ] ) oder atomic_store ( p, ( struct S ) { a, b } ) ; ), wird das Komma als Makroargument-Trennzeichen interpretiert, was zu einem Kompilierungsfehler aufgrund von Argumentanzahl-Ungleichheit führt.

# 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 eingeschlossen:

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")
(seit C99)

Ein ## -Operator zwischen zwei aufeinanderfolgenden Bezeichnern in der replacement-list führt eine Parameterersetzung für die beiden Bezeichner durch und verkettet dann das Ergebnis. Dieser Vorgang wird "Konkatenation" oder "Token-Pasting" genannt. Nur Token, die zusammen ein gültiges Token bilden, dürfen verknüpft werden: Bezeichner, die einen längeren Bezeichner bilden, Ziffern, die eine Zahl bilden, oder Operatoren + und = , die einen += bilden. Ein Kommentar kann nicht durch Verknüpfen 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 an, die es erlaubt, dass ## nach einem Komma und vor __VA_ARGS__ erscheint, wobei das ## in diesem Fall nichts bewirkt, wenn __VA_ARGS__ nicht leer ist, aber das Komma entfernt, wenn __VA_ARGS__ leer ist: Dies ermöglicht die Definition von Makros wie fprintf ( stderr , format, ##__VA_ARGS__) .

Die Reihenfolge der Auswertung der # - und ## -Operatoren ist nicht spezifiziert.

#undef Direktive

Die #undef -Direktive hebt die Definition des Bezeichners auf, das heißt, sie macht die vorherige Definition des Bezeichners durch die #define -Direktive rückgängig. Wenn der Bezeichner kein assoziiertes Makro besitzt, wird die Direktive ignoriert.

Vordefinierte Makros

Die folgenden Makronamen sind in jeder Übersetzungseinheit vordefiniert:

__STDC__
expandiert zur Ganzzahlkonstante 1 . Dieses Makro soll eine konforme Implementierung anzeigen
(Makrokonstante)
__STDC_VERSION__
(C95)
expandiert zu einer Ganzzahlkonstante vom Typ long , deren Wert mit jeder Version des C-Standards steigt:
  • 199409L (C95)
  • 199901L (C99)
  • 201112L (C11)
  • 201710L (C17)
  • 202311L (C23)
    (Makrokonstante)
__STDC_HOSTED__
(C99)
expandiert zur Ganzzahlkonstante 1 , wenn die Implementierung gehostet ist (unter einem Betriebssystem läuft), 0 , wenn sie eigenständig ist (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 Quelldatei, eine Ganzzahlkonstante, kann durch die #line -Direktive geändert werden
(Makrokonstante)
__DATE__
expandiert zum Übersetzungsdatum, ein Zeichenkettenliteral der Form „Mmm dd yyyy“. Der Monatsname wird wie durch asctime erzeugt und das erste Zeichen von „dd“ ist ein Leerzeichen, wenn der Tag des Monats kleiner als 10 ist
(Makrokonstante)
__TIME__
expandiert zur Übersetzungszeit, ein Zeichenkettenliteral der Form „hh:mm:ss“, wie in der durch asctime ( ) erzeugten Zeit
(Makrokonstante)
__STDC_UTF_16__
(C23)
expandiert zu 1 , um anzuzeigen, dass char16_t UTF-16-Kodierung verwendet
(Makrokonstante)
__STDC_UTF_32__
(C23)
expandiert zu 1 , um anzuzeigen, dass char32_t UTF-32-Kodierung verwendet
(Makrokonstante)
__STDC_EMBED_NOT_FOUND__ __STDC_EMBED_FOUND__ __STDC_EMBED_EMPTY__
(C23)
expandieren zu 0 , 1 , bzw. 2
(Makrokonstante)

Die folgenden zusätzlichen Makronamen können von einer Implementierung vordefiniert sein:

__STDC_ISO_10646__
(C99)
expandiert zu einer Integer-Konstante der Form yyyymmL , falls wchar_t Unicode verwendet; das Datum gibt die neueste unterstützte Unicode-Revision an
(Makrokonstante)
__STDC_IEC_559__
(C99) (in C23 veraltet)
expandiert zu 1 wenn IEC 60559 unterstützt wird
(Makrokonstante)
__STDC_IEC_559_COMPLEX__
(C99) (veraltet in C23)
expandiert zu 1 falls IEC 60559-Komplexarithmetik unterstützt wird
(Makrokonstante)
__STDC_UTF_16__
(C11)
erweitert zu 1 falls char16_t UTF-16-Kodierung verwendet
(Makrokonstante)
__STDC_UTF_32__
(C11)
erweitert zu 1 falls char32_t UTF-32-Kodierung verwendet
(Makrokonstante)
__STDC_MB_MIGHT_NEQ_WC__
(C99)
expandiert zu 1 falls 'x' == L 'x' für ein Mitglied des Basiszeichensatzes falsch sein könnte, wie z.B. auf EBCDIC-basierten Systemen, die Unicode für wchar_t verwenden
(Makrokonstante)
__STDC_ANALYZABLE__
(C11)
expandiert zu 1 falls Analysierbarkeit unterstützt wird
(Makrokonstante)
__STDC_LIB_EXT1__
(C11)
erweitert sich zu einer ganzzahligen Konstante 201112L falls grenzprüfende Schnittstellen unterstützt werden
(Makrokonstante)
__STDC_NO_ATOMICS__
(C11)
expandiert zu 1 falls atomic Typen und die atomic operations library nicht unterstützt werden
(Makrokonstante)
__STDC_NO_COMPLEX__
(C11)
expandiert zu 1 falls komplexe Typen und die komplexe Mathematikbibliothek nicht unterstützt werden
(Makrokonstante)
__STDC_NO_THREADS__
(C11)
expandiert zu 1 falls Multithreading nicht unterstützt wird
(Makrokonstante)
__STDC_NO_VLA__
(C11)
expandiert zu 1 falls variable-length arrays und variably-modified types (bis C23) von automatic storage duration (seit C23) nicht unterstützt werden
(Makrokonstante)
__STDC_IEC_60559_BFP__
(C23)
erweitert sich zu 202311L wenn IEC 60559 binäre Gleitkommaarithmetik unterstützt wird
(Makrokonstante)
__STDC_IEC_60559_DFP__
(C23)
expandiert zu 202311L falls IEC 60559 Dezimal-Gleitkommaarithmetik unterstützt wird
(Makrokonstante)
__STDC_IEC_60559_COMPLEX__
(C23)
erweitert sich zu 202311L falls IEC 60559-Komplexarithmetik unterstützt wird
(Makrokonstante)
__STDC_IEC_60559_TYPES__
(C23)
erweitert zu 202311L falls IEC 60559 Austausch- und erweiterte Typen unterstützt werden
(Makrokonstante)

Die Werte dieser Makros (außer __FILE__ und __LINE__ ) bleiben während der gesamten Übersetzungseinheit konstant. Versuche, diese Makros neu zu definieren oder ihre Definition aufzuheben, führen zu undefiniertem Verhalten.

Die vordefinierte Variable __func__ (siehe Funktionsdefinition für Details) ist kein Präprozessor-Makro, obwohl sie manchmal zusammen mit __FILE__ und __LINE__ verwendet wird, z.B. durch assert .

(seit C99)

Beispiel

#include <stdio.h>
// make function factory and use it
#define FUNCTION(name, a) int fun_##name(int x) { return (a) * x; }
FUNCTION(quadruple, 4)
FUNCTION(double, 2)
#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) puts( #a )
int main(void)
{
    printf("quadruple(13): %d\n", fun_quadruple(13));
    printf("double(21): %d\n", fun_double(21));
    printf("%d\n", FUNCTION);
    OUTPUT(billion); // note the lack of quotes
}

Ausgabe:

quadruple(13): 52
double(21): 42
34
billion

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
DR 321 C99 Es war unklar, ob L 'x' == 'x' innerhalb des Basiszeichensatzes immer gilt __STDC_MB_MIGHT_NEQ_WC__ für diesen Zweck hinzugefügt

Referenzen

  • C23-Standard (ISO/IEC 9899:2024):
  • 6.10.4 Makroersetzung (S: 187-184)
  • 6.10.9 Vordefinierte Makronamen (S: 186-188)
  • C17-Standard (ISO/IEC 9899:2018):
  • 6.10.3 Makroersetzung (S: 121-126)
  • 6.10.8 Vordefinierte Makronamen (S: 127-129)
  • C11-Standard (ISO/IEC 9899:2011):
  • 6.10.3 Makroersetzung (S: 166-173)
  • 6.10.8 Vordefinierte Makronamen (S: 175-176)
  • C99-Standard (ISO/IEC 9899:1999):
  • 6.10.3 Makroersetzung (S: 151-158)
  • 6.10.8 Vordefinierte Makronamen (S: 160-161)
  • C89/C90 Standard (ISO/IEC 9899:1990):
  • 3.8.3 Makroersetzung
  • 3.8.8 Vordefinierte Makronamen

Siehe auch

C++-Dokumentation für Ersetzen von Textmakros