You can define C++ macros to substitute text in your source file.
This section is organized into the following topics:
Syntax
The general syntax for a macro replacement directive is:
macro-directive ::=
#define identifier [replacement-list]
#define identifier( [identifier-list] ) [replacement-list]
#undef identifier
replacement-list ::=
token
replacement-list token
A #define preprocessing directive defines the identifier as a macro name that represents the
replacement-list. This is of the form:
#define identifier [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, 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 compilation unit.
The replacement-list must fit on one line. If the line becomes too long, it can be
broken up into several lines provided that all lines but the last are terminated by a
backslash (\) character. The following is an example:
#define mac very very long\
replacement string
The backslash character \ must be the last character on the line.
You cannot add any spaces or comments after it.
Macros can be redefined without an intervening #undef directive.
Any parameter used must agree in number
and spelling with the original definition, and the replacement lists must
be identical. All white space within
replacement-list is treated as a single blank space regardless
of the number of white-space characters you
use. For example, the following #define directives are equivalent:
#define foo x + y
#define foo x + y
The replacement-list may be empty. If the token list is not provided, the macro name is replaced with no
characters.
Macros with Parameters
You can create macros that have parameters. The syntax of the #define directive
that includes formal parameters is as follows:
#define identifier([identifier-list]) [replacement-list]
The macro name is identifier. The formal parameters are provided by the
identifier-list enclosed in parentheses. The open parenthesis "(" must
immediately follow the identifier with no intervening white space.
If there is a space between the identifier and the open parenthesis "(",
the macro is
defined as if it were the first form and the replacement-list begins
with the opwn prenthesis "(" 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 parenthesized list
following the macro name. Commas 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.
Specifying String Literals with the # Operator
If a formal parameter in the macro definition directive's replacement string is
preceded by 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, available only with the ANSI C preprocessor, may be used to turn
macro arguments into strings. This feature is often used with the fact that
HP aC++ concatenates adjacent strings.
Example:
#include <iostream.h>
#define display(arg) cout << #arg << "\n" //define the macro
int main()
{
display(any string you want to use); //use the macro
}
After HP aC++ expands the macro definition in the preceding program, the following code results:
...
main ()
{
cout << "any string you want to use" << "\n";
}
Concatenating Tokens with the ## Operator
Use the ## operator within macros to create a single token out of two other tokens.
(Usually, one of these two tokens is the actual argument for a macro-parameter.)
Upon expansion of the macro, each instance of the ## operator is deleted and
the tokens preceding and following the ## are concatenated into a single token.
Example 1:
// define the macro; the ## operator
// concatenates arg1 with arg2
#define concat(arg1,arg2) arg1 ## arg2
int main()
{
int concat(fire,fly);
concat(fire,fly) = 1;
printf("%d \n",concat(fire,fly));
}
Preprocessing the preceding program yields the following:
int main()
{
int firefly ;
firefly = 1;
printf("%d \n",firefly );
}
Example 2:
You can use the # and ## operators together:
#include <iostream.h>
#define show_me(arg) int var##arg=arg;\
cout << "var" #arg " is " << var##arg << "\n";
int main()
{
show_me(1);
}
Preprocessing this example yields the following code for the main procedure:
int main()
{
int var1=1; cout << "var" "1" " is " << var1 << "\n";
}
After compiling the code with aCC and running the resulting executable file, you get the
following results:
var1 is 1
Spaces around the # and ## are optional.
In both the # and ## operations, the arguments are substituted as is, without any
intermediate expansion. After these operations are completed, the entire replacement
text is rescanned for further macro expansions.
Note: The result of the preprocessor concatenation operator ## must be
a _single_ token. In particular, the use of ## to concatenate strings
is redundant and not legal C or C++. For example:
#include <stdio.h>
#define concat_token(a, b) a##b
#define concat_string(a, b) a b
int main() {
// Wrong:
printf("%s\n", concat_token("Hello,", " World!"));
// Correct:
printf("%s\n", concat_string("Hello,", " World!"));
// Best: (macro not needed at all!):
printf("%s\n", "Hello," " World!");
}
Using Macros to Define Constants
The most common use of the macro replacement is in defining a constant.
In C++ you can also declare constants using the keyword const.
Rather than explicitly putting constant values in a program, you can name
the constants using macros, then use the names in place of the constants.
By changing the definition of the macro, you can more easily change the program.
In the following example, the array x is dimensioned using the macro
ARRAY_SIZE rather than the constant 1000.
#define ARRAY_SIZE 1000
float x[ARRAY_SIZE];
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 changes and so do all of the expressions that make use of the dimension.
Other Macros
Some other common macros include:
- #define FALSE 0
- #define TRUE 1
- #define MAX(x,y)
The #define MAX(x,y) macro is more complex. It has two parameters and
produces an inline expression which is equal to the maximum of its two
parameters:
#define MAX(x,y) ((x) > (y) ? (x) : (y))
Note: Parentheses surrounding each argument and the resulting
expression ensure that the precedences of the arguments and the result
interact properly with any other operators that might be used with the
MAX macro.
Because each argument to the MAX macro appears in the token
string more than once, the actual arguments to the MAX macro may have
undesirable side effects.
The following example might not work as expected because the argument a is
incremented two times when a is the maximum:
i = MAX(a++, b);
This is expanded to:
i = ((a) > (b) ? (a) : (b))
Given the above macro definition, the statement
i = MAX(a, b+2);
is expanded to:
i = ((a) > (b+2) ? (a) : (b+2));
More Examples:
// This macro tests a number and returns TRUE if
// the number is odd. It returns FALSE otherwise.
#define isodd(n) ( ((n % 2) == 1) ? (TRUE) : (FALSE))
// This macro skips white spaces.
#define eatspace()while((c=getc(input))==c=='\n'c\
= '\t' )
Using Constants and Inline Functions Instead of Macros
In C++ you can use named constants and inline functions to achieve results
similar to using macros. You can use const variables in place of macros.
You can also use inline functions in many C++ programs where you would have
used a function-like macro in a C program. Using inline functions reduces the
likelihood of unintended side effects, since they have return types and
generate their own temporary variables where necessary.
Example:
The following program illustrates the replacement of a macro with an inline function:
#include <stream.h>
#define distance1(rate,time) (rate * time)
// replaced by :
inline int distance2 ( int rate, int time )
{
return ( rate * time );
}
int main()
{
int i1 = 3, i2 = 3;
printf("Distance from macro : %d\n",
distance1(i1,i2) );
printf("Distance from inline function : %d\n",
distance2(i1,i2) );
}
Predefined Macros
The following list describes the complete set of predefined macros that
produce special information. They cannot be undefined nor changed.
-
__cplusplus produces the decimal constant 199711L, indicating
that the implementation supports ANSI/ISO C++ International Standard
features.
#if (__cplusplus >= 199711L)
#include
#else
#include
- __DATE__ produces the date of compilation in the form Mmm dd yyyy.
- __FILE__ produces the name of the file being compiled.
- __HP_aCC identifies the HP aC++ compiler driver version. It is represented up to
six digits in the format mmnnxx, where mm is the major version number, nn
is the minor version number, and xx is any extension. For example, for
version A.06.00, __HP_aCC=60000.
- __HP_cc identifies the HP C compiler driver version. It is represented up to
six digits in the format mmnnxx, where mm is the major version number, nn
is the minor version number, and xx is any extension. For example, for
version A.06.00, __HP_cc=60000.
- __LINE__ produces the current source line number.
- __LP64__ is defined for +DD64.
- __ia64 is defined.
- _ILP32 is defined for +DD32.
- _LP64 is defined for +DD64.
- __STDCPP__ produces the decimal constant 1, indicating that the
preprocessor is in ANSI C/C++ mode.
- __TIME__ produces the time of compilation in the form hh:mm:ss.
|