The #define Directive

You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are

Syntax

#defineidentifier token-stringopt

#defineidentifier(identifier, ...,identifier)token-stringopt

The #define directive substitutes token-string for all subsequent occurrences of an identifier in the source file. The identifier is replaced only when it forms a token. (For information on tokens, see “Tokens” in Chapter 1, on topic .) For instance, identifier is not replaced if it appears in a comment, within a string, or as part of a longer identifier.

A #define without a token-string removes occurrences of identifier from the source file. The identifier remains defined and can be tested using the #if defined and #ifdef directives.

The token-string argument consists of a series of tokens, such as keywords, constants, or complete statements. One or more white-space characters must separate token-string from identifier. This white space is not considered part of the substituted text, nor is any white space following the last token of the text.

Formal parameter names appear in token-string to mark the places where actual values are substituted. Each parameter name can appear more than once in token-string, 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. Liberal use of parentheses ensures that complicated actual arguments are not interpreted correctly.

With the second syntax form, an optional list of parameters for a macro appears in parentheses. References to the identifier after the original definition replace each occurrence of identifier( identifieropt, ..., identifieropt ) with a version of the token-string argument that has actual arguments substituted for formal parameters.

The formal parameters in the list are separated by commas. Each name in the list must be unique, and the list must be enclosed in parentheses. No spaces can separate identifier and the opening parenthesis. Use line concatenation—place a backslash (\) before the newline character—for long directives on multiple source lines. The scope of a formal parameter name extends to the new line that ends token-string.

When a macro has been defined in the second syntax form, subsequent textual instances followed by an argument list constitute a macro call. The actual arguments following an instance of identifier in the source file are matched to the corresponding formal parameters in the macro definition. Each formal parameter in token-string that is not preceded by a stringizing (#), charizing (#@), or token-pasting (##) operator, or followed by a ## operator, is replaced by the corresponding actual argument. Any macros in the actual argument are expanded before it replaces the formal parameter. (The operators are described in “Preprocessor Operators”.)

The following examples of macros with arguments illustrate the second form of the #define syntax:

// Macro to define cursor lines

#define CURSOR(top, bottom) ((top) << 8) | bottom))

// Macro to get a random integer with a specified range

#define getrandom(min, max) \

((rand()%(int)(((max) + 1)-(min)))+ (min))

Arguments with side effects sometimes cause macros to produce unexpected results. A given formal parameter may appear more than once in token-string. If that formal 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 (##)”).

Note:

As mentioned above, unexpected results such as those caused by calling the getrandom macro with an expression such as getrandom(i++, j) can be eliminated using inline functions instead of macros.

The #undef directive causes an identifier's preprocessor definition to be forgotten. See “The #undef Directive”.

If the name of the macro being defined occurs in token-string (even as a result of another macro expansion), it is not expanded.

A second #define for the same identifier generates an error unless the second token sequence is identical to the first.

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. The Microsoft C/C++ compiler allows this behavior but generate warnings. For example, these macros are equivalent for C/C++ but generate warnings:

#define test( f1, f2 ) ( f1 * f2 )

#define test( a1, a2 ) ( a1 * a2 )¨

This example illustrates the #define directive:

#define WIDTH 80

#define LENGTH ( WIDTH + 10 )

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.

Microsoft Specific

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.¨

Preprocessor Operators

Four preprocessor-specific operators are used in the context of the #define directive. (See “The #if, #elif, #else, and #endif Directives” on page 379 for information on the defined operator.) This list gives a short summary of each of the preprocessor directives described in the following sections:

Operator Action

Stringizing operator (#) Causes the corresponding actual argument to be enclosed in double quotation marks
Charizing operator (#@) Causes the corresponding argument to be enclosed in single quotation marks and to be treated as a character
Token-pasting operator (##) Allows tokens used as actual arguments to be concatenated to form other tokens
defined operator Simplifies the writing of compound expressions in certain macro directives

Stringizing Operator (#)

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 formal parameter in the macro definition, the actual 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 formal parameter within the macro definition.

White space preceding the first token of the actual argument and following the last token of the actual argument is ignored. Any white space between the tokens in the actual argument is reduced to a single white space in the resulting string literal. Thus, if a comment occurs between two tokens in the actual 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 (\) character), 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 quote" );

}

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 quote\"" “\n” );

}

When the program is run, screen output for each line is as follows:

In quotes in the printf function call

“In quotes when printed to the screen”

“This: \” prints an escaped double quotation mark"

Microsoft Specific

The Microsoft C (versions 6.0 and earlier) extension to the ANSI C standard that previously expanded macro formal arguments appearing inside 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 arguments of macros. If #@ precedes a formal parameter in the definition of the macro, the actual 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.

Token-Pasting Operator (##)

The double-number-sign or “token-pasting” operator (##), which is 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 formal parameter in a macro definition is preceded or followed by the token-pasting operator, the formal parameter is immediately replaced by the unexpanded actual argument. Macro expansion is not performed on the argument prior to replacement.

Then each occurrence of the token-pasting operator in token-string 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 scanned for possible replacement if it represents a macro name. The identifier 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 )

If token9 is declared and the macro is called with a numeric argument like

paster( 9 );

the macro yields

printf( “token” “9" ” = %d", token9 );

which becomes

printf( “token9 = %d”, token9 );