The #define
directive specifies a macro identifier and
a replacement list, and terminates with a new-line character. The
replacement list, a sequence of preprocessing tokens, is substituted
for every subsequent occurrence of that macro identifier in the
program text, unless the identifier occurs inside a character
constant, a comment, or a literal string. The #undef
directive is used to cancel a definition for a macro.
A macro definition is independent of block structure, and is in
effect from the #define
directive that defines it until
either a corresponding #undef
directive or the end of
the compilation unit is encountered.
The #define
directive has the following syntax:
#define identifier replacement-list newline
#define identifier ( identifier-list(opt) ) replacement-list newline
If the replacement-list is empty, subsequent occurrences of the identifier are deleted from the source file.
The first form of the #define
directive is called
an object-like macro. The second form is called a
function-like macro.
The #undef
directive has the following syntax:
#undef identifier newline
This directive cancels a previous definition of the identifier by
#define
. Redefining a macro previously defined is not
legal, unless the new definition is precisely the same as the old.
The replacement list in the macro definition, as well as arguments in a function-like macro reference, can contain other macro references. DEC C does not limit the depth to which such references can be nested.
For a given macro definition, any macro names contained in the replacement list are themselves replaced by their currently specified replacement lists. If a macro name being defined is contained in its own replacement list or in a nested replacement list, it is not replaced. These nonreplaced macro names are then no longer available for further replacement, even if they are later examined in contexts in which they would otherwise be replaced.
The following example shows nested #define
directives:
/* Show multiple substitutions and listing format. */ #define AUTHOR james + LAST main() { int writer,james,michener,joyce; #define LAST michener writer = AUTHOR; #undef LAST #define LAST joyce writer = AUTHOR; }
After this example is compiled with the appropriate options to show intermediate macro expansions, the following listing results:
1 /* Show multiple substitutions and listing format. */ 2 3 #define AUTHOR james + LAST 4 5 main() 6 { 7 int writer, james, michener, joyce; 8 9 #define LAST michener 10 writer = AUTHOR; 10.1 james + LAST 10.2 michener 11 #undef LAST 12 #define LAST joyce 13 writer = AUTHOR; 13.1 james + LAST 13.2 joyce 14 }
On the first pass, the compiler replaces the identifier
AUTHOR
with the replacement list james
+ LAST
. On the second pass, the compiler replaces
the identifier LAST
with its currently defined
replacement list value. At line 9, the replacement list value for
LAST
is the identifier michener
, so
michener
is substituted at line 10. At line 12, the
replacement list value for LAST
is redefined to be the
identifier joyce
, so joyce
is substituted
at line 13.
The #define
directive may be continued onto subsequent
lines if necessary. To do this, end each line to be continued with
a backslash (\) immediately followed by a new-line character.
The backslash and new-line characters do not become part of the
definition. The first character in the next line is logically
adjacent to the character that immediately precedes the backslash.
The backslash/newline as a continuation sequence is valid anywhere.
However, comments within the definition line can be continued
without the backslash/newline.
If you plan to port programs to and from other C implementations, take care in choosing which macro definitions to use within your programs, because some implementations define different macros than others.
A preprocessing directive of the following form defines an object- like macro that causes each subsequent occurrence of the macro name to be replaced by the replacement list:
#define identifier replacement-list newline
An object like macro may be redefined by another
#define
directive provided that the second definition
is an object-like macro definition and the two replacement lists are
identical. This means that two files, each with a definition of a
certain macro, must be consistent in that definition.
The object-like form of macro definition defines a descriptive name
for a frequently used token. A common use of the directive is to
define the end-of-file (EOF
) indicator as follows:
#define EOF (-1)
The function-like form of macro definition includes a list of parameters. References to such macros look like function calls. When a function is called, control passes from the program to the function at run time; when a macro is referenced, source code is inserted into the program at compile time. The parameters are replaced by the corresponding arguments, and the text is inserted into the program stream.
If the replacement list is omitted from the macro definition, the entire macro reference disappears from the source text.
The library macro _toupper
, available on some systems
in the ctype.h
header file, is a good example of macro
replacement. This macro is defined as follows:
#define _toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) & 0X5F : (c))
When the macro _toupper
is referenced, the compiler
replaces the macro and its parameter with the replacement list from
the directive, substituting the argument of the macro reference for
each occurrence of the parameter (c
in this case) in
the replacement list.
The replacement list of C source code can be translated in the
following manner: if parameter c
is a lowercase
letter (between 'a'
and 'z'
), the
expression evaluates to an uppercase letter (c & 0X5F
); otherwise, it evaluates to the character as specified. This
replacement list uses the if-then-else conditional operator
(?:
). For more information about the conditional
operator, see Section 6.6. For more
information about the bitwise operators, see Section 6.5.6.
Preprocessor directives and macro references have syntax that is independent of the C language. Follow these rules when specifying macro definitions:
#define
directive anywhere that the delta symbol ()
appears in the following example:
# define name( parm1 , parm2 ) \ token-string
Spaces, tabs, and comments are replaced by a single space.
define
.
Follow these rules when specifying macro references:
name ( arg1 , arg2 )
It is not good programming practice to specify macro arguments
that use the increment (++), decrement (- -), and assignment
operators (such as +=) or other arguments that can cause side
effects. For example, do not pass the following argument to the
_toupper
macro:
_toupper(p++)
When the argument p++
is substituted in the macro
definition, the effect within the program stream is as follows:
((p++) >= 'a' && (p++) <= 'z' ? (p++) & 0X5F : (p++))
Because p
is being incremented, it does not have the
same value for each occurrence in this macro replacement. Even if
you are aware of possible side effects, the replacement lists within
macro definitions can be changed, which changes the side effects
without warning.
The #
preprocessor operator is used to convert the
argument that follows it to a string literal. The preprocessor
operator #
can be used only in a function-like macro
definition. For example:
#include <stdio.h> #define PR(id) printf("The value of " #id " is %d\n", id) main() { int i = 10; PR(i); }
The output produced is:
The value of i is 10
The macro call expands in the following steps:
/*1*/ printf("The value of " #id " is %d\n", id) /*2*/ printf("The value of " "i" " is %d\n", 10) /*3*/ printf("The value of i is %d\n", 10)
The unary #
operator produces a string from its
operand. This example also uses the fact that adjacent string
literals are concatenated. If the operand to #
contains
double quotes or escape sequences, they are also expanded. For
example:
#include <stdio.h> #define M(arg) printf(#arg " is %s\n", arg) main() { M("a\nb\tc"); }
The macro call expands using the following steps:
/*1*/ printf(#arg " is %s\n", arg) /*2*/ printf("\"a\\nb\\tc\"" " is %s\n", "a\nb\tc"); /*3*/ printf("\"a\\nb\\tc\" is %s\n", "a\nb\tc");
The ##
preprocessor operator is used to concatenate two
tokens into a third valid token, as in the following example:
#define glue(a,b) a ## b main() { int wholenum = 5000; printf("%d", glue(whole,num)); }
The preprocessor converts the line printf("%d",
glue(whole,num));
into printf("%d", wholenum);
,
and when executed, the program prints 5000. If the result is not a
valid token, an error occurs when the tokens are concatenated.
In DEC C, the ##
operator
is evaluated before any #
operators on the line.
##
and #
operators group left-to-right.