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 \ 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 parenthesis "(", the macro is
defined as if it were the first form and 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 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 used by C/C++ programmers include:
- #define FALSE 0
- #define TRUE 1
- #define MAX(x,y)
The #define MAX 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
199707L, indicating that the implementation supports
ANSI/ISO C++ International Standard features.
#if (__cplusplus >= 199707L)
#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 as a six digit number 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.01.21, __HP_aCC=012100
Note, the version number is generated for HP aC++
versions A.01.21 or A.03.25 or later. The __HP_aCC
predefined macro was introduced in HP aC++ version A.01.15.
It's value was 1 for HP aC++ versions A.01.15, A.01.18, and
A.03.13.
__LINE__ produces the current source line
number.
__LP64__ is defined for 64-bit mode on
PA-RISC 2.0 systems.
__RISC2_0__ is defined for both the 32-bit
and the 64-bit mode on PA-RISC 2.0 systems.
__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.
For More Information
To use some HP-UX system functions you may need to define the
symbol __HPUX_SOURCE. See the stdsyms(5) man page
if it is installed on your system, or in the HP-UX
Reference Manual. (If you see the message "Man page could
not be formatted," ensure the man page is installed.)
|