HP 3000 Manuals

Macro Replacement [ HP C/iX Reference Manual ] MPE/iX 5.0 Documentation


HP C/iX Reference Manual

Macro Replacement 

You can define text substitutions in your source file with C macro
definitions.

Syntax 

     macro-directive ::=
         #define identifier [replacement-list] 
         #define identifier ( [identifier-list] )
              [replacement-list] 
         #undef identifier 

     replacement-list ::=
         token 
         replacement-list token 

Description 

A #define preprocessing directive of the form:

     #define identifier [replacement-list] 

defines the identifier as a macro name that represents the replacement
list.  The macro name is then replaced by the list of tokens wherever it
appears in the source file (except inside of a string or character
constant, or comment).  A macro definition remains in force until it is
undefined through the use of the #undef directive or until the end of the
translation unit.

Macros can be redefined without an intervening #undef directive.  Any
parameters used must agree in number and spelling, and the replacement
lists must be identical.  All whitespace is treated equally.

The replacement-list may be empty.  If the token list is not provided,
the macro name is replaced with no characters.

If the define takes the form

     #define identifier ([identifier-list]) replacement-list 

a macro with formal parameters is defined.  The macro name is the
identifier and the formal parameters are provided by the identifier-list 
which is enclosed in parentheses.  The first parenthesis must immediately
follow the identifier with no intervening whitespace.  If there is a
space between the identifier and the (, the macro is defined as if it
were the first form and that the replacement list begins with the ( 
character.

The formal parameters to the macro are separated with commas.  They may
or may not appear in the replacement list.  When the macro is invoked,
the actual arguments are placed in a parentheses-enclosed list following
the macro name.  Comma tokens enclosed in additional matching pairs of
parentheses do not separate arguments but are themselves components of
arguments.

The actual arguments replace the formal parameters in the token string
when the macro is invoked.

If a formal parameter in the macro definition directive's token string
follows a # operator, it is replaced by the corresponding argument from
the macro invocation, preceded and followed by a double-quote character
(") to create a string literal.  This feature may be used to turn macro
arguments into strings.  This feature is often used with the fact that
the compiler concatenates adjacent strings.

After all replacements have taken place during macro invocation, each
instance of the special ## token is deleted and the tokens preceding and
following the ## are concatenated into a single token.  This is useful in
forming unique variable names within macros.

The following example illustrates the use of the # operator for creating
string literals out of arguments and concatenating tokens:

     #define debug(s, t) printf("x" # s "= %d, x" # t " %s", x##s, x##t)

Invoked as:  debug(1, 2);

Results in:

     printf("x" "1" "= %d, x" "2" "= %s", x1, x2);

which, after concatenation, results in:

     printf("x1= %d, x2= %s", x1, x2);

Spaces around the # and ## are optional.


NOTE The # and ## operators are only supported in ANSI mode.
The most common use of the macro replacement is in defining a constant. Rather than hard coding constants in a program, you can name the constants using macros then use the names in place of actual constants. By changing the definition of the macro, you can more easily change the program: #define ARRAY_SIZE 1000 float x[ARRAY_SIZE]; In this example, the array x is dimensioned using the macro ARRAY_SIZE rather than the constant 1000. Note that expressions that may use the array can also use the macro instead of the actual constant: for(i=0; i<ARRAY_SIZE; ++i) f+=x[i]; Changing the dimension of x means only changing the macro for ARRAY_SIZE; the dimension will change and so will all the expressions that make use of the dimension. Some other common macros used by C programmers include: #define FALSE 0 #define TRUE 1 The following macro is more complex. It has two parameters and will produce an in-line expression which is equal to the maximum of its two parameters: #define MAX(x,y) ((x) > (y) ? (x) : (y)) Parentheses surrounding each argument and the resulting expression insure that the precedences of the arguments and the result will not improperly interact with any other operators that might be used with the MAX macro. Using a macro definition for MAX has some advantages over a function definition. First, it executes faster because the macro generates in-line code, avoiding the overhead of a function call. Second, the MAX macro accepts any argument types. A functional implementation of MAX would be restricted to the types defined for the function. Note further that because each argument to the MAX macro appears in the token string more than once, check to be sure that the actual arguments to the MAX macro do not have any "side effects." The following example MAX(a++, b); might not work as expected because the argument a is incremented two times when a is the maximum. The following statement i = MAX(a, b+2); is expanded to: i = ((a) > (b+2) ? (a) : (b+2)); Examples #define isodd(n) ( ((n % 2) == 1) ? (TRUE) : (FALSE)) /* This macro tests a number and returns TRUE if the number is odd. It will */ /* return FALSE otherwise. */ #define eatspace() while( (c=getc(input)) == ' ' || c == '\n' || c == '\t' ); /* This macro skips white spaces. */


MPE/iX 5.0 Documentation