You can use the #define directive to give a meaningful name to a constant or statement in your program. The ways to specify a manifest constant or a macro are given by this syntax:
control-line :
#define identifier replacement-list new-line /* Macro without parameters */
#define identifier (identifier-list opt new-line) replacement-list new-line
The #define directive substitutes replacement-list for all subsequent occurrences of identifier in the source file. The identifier is replaced only when it forms a token. For instance, identifier is not replaced if it appears in a comment, within a string, or as part of a longer identifier.
The replacement-list argument consists of a series of tokens, such as keywords, constants, or complete statements. One or more white-space characters must separate replacement-list from identifier. This initial white space is not considered part of the substituted text, nor is any white space following the last token of the text.
If an identifier-list appears after identifier, the #define directive replaces each occurrence of identifier (identifier-list) with a version of the replacement-list argument that has arguments substituted for parameters. The identifier-list is a list of parameters for a macro.
When a macro with parameters has been defined, subsequent textual instances followed by an identifier-list constitute a macro call. The arguments following an instance of identifier in the source file are matched to the corresponding parameters of identifier-list. Each parameter in replacement-list that is not preceded by a stringizing (#), charizing (#@), or token-pasting (##) operator, or followed by a token-pasting operator, is replaced by the corresponding argument. Any macros in the argument are expanded before the argument replaces the parameter. (The preprocessor operators are described on topic .)
Parameter names appear in replacement-list to mark the places where actual values are substituted. A parameter name can appear more than once in replacement-list, and the names can appear in any order. The number of arguments in the call must match the number of parameters in the macro definition. The liberal use of parentheses ensures that the precedence of complicated arguments is not misinterpreted. If the name of the macro being defined occurs in replacement-list (even as a result of another macro expansion), it is not expanded.
The parameters in the identifier-list are separated by commas. Each name must be unique. No spaces can separate identifier and the opening parenthesis. Use line concatenation (placing a backslash (\) before the newline character) for long directives on multiple source lines. The scope of a parameter name extends to the new line that ends replacement-list.
This example illustrates the #define directive for manifest constants and macros:
#define WIDTH 80 /* Manifest constant */
#define LENGTH ( WIDTH + 10 ) /* Macro */
The first statement defines the identifier WIDTH as the integer constant 80 and defines LENGTH in terms of WIDTH and the integer constant 10. Each occurrence of LENGTH is replaced by ( WIDTH + 10 ). In turn, each occurrence of WIDTH + 10 is replaced by the expression ( 80 + 10 ). The parentheses around WIDTH + 10 are important because they control the interpretation in statements such as the following:
var = LENGTH * 20;
After the preprocessing stage the statement becomes
var = ( 80 + 10 ) * 20;
which evaluates to 1800. Without parentheses, the result is
var = 80 + 10 * 20;
which evaluates to 280.
Arguments with side effects sometimes cause macros to produce unexpected results. A given parameter may appear more than once in replacement-list. If that parameter is replaced by an expression with side effects, the expression, with its side effects, may be evaluated more than once (see examples in “Token-Pasting Operator”).
A #define without a replacement-list removes occurrences of identifier from the source file. The identifier is still considered defined, however, and yields the value 1 when tested with the #if defined directive (discussed in “The defined Operator”). A second #define for the same identifier generates an error unless the second token sequence is identical to the first.
The #undef directive causes an identifier's preprocess definition to be removed. See “The #undef Directive”.
Microsoft Specific
Microsoft C version 6.0 allows a macro to be redefined provided it is lexically identical to the previous definition. ANSI C considers macro redefinition an error. C 7.0 allows this behavior but generates a warning. For example these macros are equivalent for C 7.0 but generate warnings since ANSI C considers this an error.
#define test( f1, f2 ) ( f1 * f2 )
#define test( a1, a2 ) ( a1 * a2 )
Defining macros and constants with the /D command-line option has the same effect as using a #define preprocessing directive at the beginning of your file. Up to 30 macros can be defined with the /D option. See topic , “The #ifdef and #ifndef Directives,” for more information about defining constants from the command line.¨
Four preprocessor-specific operators are used in the context of the #define directive. This list gives a summary of each. The first three preprocessor operators are discussed in the next three sections. The fourth, the defined operator, is discussed on topic .
Microsoft Specific
Charizing operator (#@)
Causes the corresponding argument to be enclosed in single quotation marks and to be treated as a character.¨
Stringizing operator (#)
Causes the corresponding argument to be enclosed in double quotation marks.
Token-pasting operator (##)
Allows tokens used as arguments to be concatenated to form other tokens.
defined operator
Simplifies the writing of compound expressions in certain macro directives. Used as part of a constant expression that can be tested in an #if block to determine if a particular identifier has been defined as a macro.
The number-sign or “stringizing” operator (#) converts macro parameters (after expansion) to string constants. It is used only with macros that take arguments. If it precedes a parameter in the macro definition, the argument passed by the macro invocation is enclosed in quotation marks and treated as a string literal. The string literal then replaces each occurrence of a combination of the stringizing operator and parameter within the macro definition.
White space preceding the first token of the argument and following the last token of the argument is ignored. Any white space between the tokens in the argument is reduced to a single white space in the resulting string literal. Thus, if a comment occurs between two tokens in the argument, it is reduced to a single white space. The resulting string literal is automatically concatenated with any adjacent string literals from which it is separated only by white space.
Further, if a character contained in the argument usually requires an escape sequence when used in a string literal—for example, the quotation-mark (“) or backslash (\) characters—the necessary escape backslash is automatically inserted before the character.
The following example shows a macro definition that includes the stringizing operator and a main function that invokes the macro:
#define stringer( x ) printf( #x "\n" )
main()
{
stringer( In quotes in the printf function call\n );
stringer( "In quotes when printed to the screen"\n );
stringer( "This: \" prints an escaped double quotation mark" );
}
Such invocations would be expanded during preprocessing, producing the following code:
main()
{
printf( "In quotes in the printf function call\n" "\n" );
printf( "\"In quotes when printed to the screen\"\n" "\n" );
printf( "\"This: \\\" prints an escaped double quotation mark\"" "\n" );
}
When the program is run, screen output for each line would be as follows:
In quotes in the printf function call
"In quotes when printed to the screen"
"This: \" prints an escaped double quotation mark"
To debug macros, compile your program with the /P command-line option. This preprocesses the source file and sends the output to a file.
Microsoft Specific
The Microsoft extension to the ANSI C standard that allowed expanded formal macro arguments to appear inside of string literals and character constants is no longer supported. Code that relied on this extension should be rewritten using the stringizing (#) operator.¨Charizing Operator (#@)
The charizing operator can be used only with the arguments of macros. If a #@precedes a parameter in the definition of the macro, the argument is enclosed in single quotation marks and treated as a character when the macro is expanded. For example,
#define makechar(x) #@x
causes the statement
a = makechar(b);
to be expanded into
a = 'b';
The single-quotation character cannot be used with the charizing operator.¨
The double-number-sign or “token-pasting” operator (##) (sometimes called the “merging” operator) is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token, and therefore cannot be the first or last token in the macro definition.
If a parameter in a macro definition is preceded or followed by the token-pasting operator, the parameter is immediately replaced by the unexpanded argument. Macro expansion is not performed on the argument prior to replacement.
Then, each occurrence of the token-pasting operator in replacement-list is removed, and the tokens preceding and following it are concatenated. The resulting token must be a valid token. If it is, the token is rescanned for possible replacement if it represents a macro name. The identifier name following the #define preprocessing directive represents the name by which the concatenated tokens will be known in the program before replacement. Each token represents a token defined elsewhere, either within the program or on the compiler command line. White space preceding or following the operator is optional.
This example illustrates use of both the “stringizing” and “token-pasting” operators in specifying program output.
#define paster( n ) printf( "token" #n " = %d", token##n )
int token9;
The macro is called with a numeric argument such as:
paster( 9 );
The macro yields
printf( "token" "9" " = %d", token9 );
which becomes
printf( "token9 = %d", token9 );