Replacing text macros
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
#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
#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:
|
|
__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
|
(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
|