Macros
Macros provide a mechanism for a token replacement, prior to compilation, with or without a set of formal, function-like parameters.
Defining Macros and Macro Expansions
The #define
directive defines a macro:
#define macro_identifier <token_sequence>
Each occurrence of macro_identifier
in the source code following this control line will be replaced in the original position with the possibly empty token_sequence
(there are some exceptions, which are discussed later). Such replacements are known as macro expansions.token_sequence
is sometimes called the body of a macro. An empty token sequence results in the removal of each affected macro identifier from the source code.
No semicolon (;
) is needed to terminate a preprocessor directive. Any character found in the token sequence, including semicolons, will appear in a macro expansion.token_sequence
terminates at the first non-backslashed new line encountered. Any sequence of whitespace, including comments in the token sequence, is replaced with a single-space character.
After each individual macro expansion, a further scan is made of the newly expanded text. This allows the possibility of using nested macros: the expanded text can contain macro identifiers that are subject to replacement. However, if the macro expands into something that looks like a preprocessing directive, such directive will not be recognized by the preprocessor. Any occurrences of the macro identifier found within literal strings, character constants, or comments in the source code will not be expanded.
A macro won’t be expanded during its own expansion (so #define MACRO MACRO
won’t expand indefinitely).
Here is an example:
/* Here are some simple macros: */ #define ERR_MSG "Out of range!" #define EVERLOOP for( ; ; ) /* which we could use like this: */ main() { EVERLOOP { ... if (error) { Lcd_Out_Cp(ERR_MSG); break; } ... } }
Attempting to redefine an already defined macro identifier will result in a warning unless a new definition is exactly the same token-by-token definition as the existing one. The preferred strategy when definitions might exist in other header files is as follows:
#ifndef BLOCK_SIZE #define BLOCK_SIZE 512 #endif
The middle line is bypassed if BLOCK_SIZE
is currently defined; if BLOCK_SIZE
is not currently defined, the middle line is invoked to define it.
Macros with Parameters
The following syntax is used to define a macro with parameters:
#define macro_identifier(<arg_list>) <token_sequence>
Note that there can be no whitespace between macro_identifier
and “(
”. The optional arg_list
is a sequence of identifiers separated by commas, like the argument list of a C function. Each comma-delimited identifier has the role of a formal argument or placeholder.
Such macros are called by writing
macro_identifier(<actual_arg_list>)
in the subsequent source code. The syntax is identical to that of a function call; indeed, many standard library C “functions” are implemented as macros. However, there are some important semantic differences.
The optional actual_arg_list
must contain the same number of comma-delimited token sequences, known as actual arguments, as found in the formal arg_list of the #define
line – there must be an actual argument for each formal argument. An error will be reported if the number of arguments in two lists is not the same.
A macro call results in two sets of replacements. First, the macro identifier and the parenthesis-enclosed arguments are replaced by the token sequence. Next, any formal arguments occurring in the token sequence are replaced by the corresponding real arguments appearing in actual_arg_list
. Like with simple macro definitions, rescanning occurs to detect any embedded macro identifiers eligible for expansion.
Here is a simple example:
/* A simple macro which returns greater of its 2 arguments: */ #define _MAX(A, B) ((A) > (B)) ? (A) : (B) /* Let's call it: */ x = _MAX(a + b, c + d); /* Preprocessor will transform the previous line into: x = ((a + b) > (c + d)) ? (a + b) : (c + d) */
It is highly recommended to put parentheses around each argument in the macro body in order to avoid possible problems with operator precedence.
Undefining Macros
The #undef
directive is used to undefine a macro.
#undef macro_identifier
The directive #undef
detaches any previous token sequence from macro_identifier
; the macro definition has been forgotten, and macro_identifier
is undefined. No macro expansion occurs within the #undef
lines.
The state of being defined or undefined is an important property of an identifier, regardless of the actual definition. The #ifdef
and #ifndef
conditional directives, used to test whether any identifier is currently defined or not, offer a flexible mechanism for controlling many aspects of a compilation.
After a macro identifier has been undefined, it can be redefined with #define
, using the same or different token sequence.
What do you think about this topic ? Send us feedback!