aCC command, your source files are automatically
preprocessed.
Include other source files at a given point, for example, to centralize
declarations or to access standard system headers such as
iostream.h.
Replace token sequences with other token sequences. In C, this technique
is frequently used to define names for constants rather
than explicitly putting the constant value into the source file.
In C++ you can also use the keyword const to define constants.
Set a predicate name or predicate name and token to be tested with conditional compilation.
Check values and flags to either compile or skip source code based on the outcome of a comparison. Useful, for example, when writing a single source for use with several different configurations.
Set the line number and file name of the next line.
Give implementation-dependent instructions, called pragmas, to the compiler. Because they are system-dependent, pragmas are not portable.
Create diagnostic messages for the compiler to issue.
Use trigraph sequences if you don't have the full C++ character set.
preprocessor-directive ::=
include-directive newline
macro-directive newline
conditional-directive newline
line-directive newline
pragma-directive newline
error-directive newline
trigraph-directive newline
warning-directive newline
#).
White-space characters may precede the # character.)
# character is followed by any number of spaces and horizontal tab
characters and a preprocessor directive.
#include <iostream.h>
#define MAC x+y
#ifdef MAC
# define x 25
# endif
#line 5 "myfile"
#pragma OPTIMIZE ON
#error "FLAG not defined!"
??=line 5 "myfile"
#warning "FLAG not defined!"
#include directive in the source file.
include-directive ::=
#include <filename>
#include "filename"
#include identifier
#include preprocessing directive causes HP aC++ to
read source input from the file named in the directive.
Usually, include files are named:
filename.h
If the file name is enclosed in angle brackets (< >), the default system directories are searched to find the named file. If the file name is enclosed in double quotation marks (&dquote; &dquote;), by default, the directory of the file containing the #include line is searched first, then directories named in -I options in left-to-right order, and last directories on a standard list.
Files that are included may contain #include directives themselves.
HP aC++ supports a nesting level of at least 35 #include files.
The arguments to the #include directive are subject to macro
replacement before being processed. Thus, if you use
a #include directive of the form #include identifier, identifier
must be a previously defined macro that when expanded
produces one of the above defined forms of the #include directive.
Refer to Macro Replacement (#define, #undef) for more information on macros.
Error messages produced by HP aC++ indicate the name
of the #include file where the error occurred, as well as
the line number within the file.
#include <iostream.h> #include "myheader.h" #ifdef MINE # define filename "file1.h" #else # define filename "file2.h" #endif #include filename
You can define C++ macros to substitute text in your source file.
macro-directive ::=
#define identifier [replacement-list]
#define identifier( [identifier-list] ) [replacement-list]
#undef identifier
replacement-list ::=
token
replacement-list token
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, 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.
NOTE: 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 "\" 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 the 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.
#define directive that includes formal parameters is as follows:
#define identifier( [identifier-list] ) [replacement-list]
The macro name is the 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.
# 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.
For 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";
}
// 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 );
}
#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#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!"); }
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:
#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 changes and so do
all of the expressions that make use of the dimension.
#define FALSE 0 #define TRUE 1
The following 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);which 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));
// 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
constvariables 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
In addition to __LINE__ and __FILE__ (refer to Line Control (#line)), HP aC++ provides the predefined macros listed below. The list describes the complete set of predefined macros that produce special information. They cannot be undefined nor changed.
__cplusplusproduces the decimal constant 199707L, 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_aCCidentifies 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.The version number is generated for HP aC++ versions A.01.21 or A.03.25 or later and is 5 digits.
The __HP_aCC predefined macro was introduced in HP aC++ version A.01.15. Its 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 +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.
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.)Assertions (#assert, #unassert)
Use #assert and #unassert to set a predicate name or predicate name and token to be tested with a #if directive. Note that you must also specify the -ext option at compile and link time.
Syntax
#assert predicate-name[token-name] #unassert predicate-name[token-name]
Description:
#assertsets thepredicate-name [token-name]to true.#unassertsets thepredicate-name [token-name]to false.Note that when testing a predicate, it must be preceded by the
#character.HP aC++ predefines the following predicates for PA-RISC 2.0 architecture:
#assert machine(parisc) #assert cpu(parisc) #assert system(unix) #assert model(lp64) // when +DA2.0W is used #assert model(ilp32) // default #assert endian(big)Example
int void main() { #assert dimensions(three) // Set predicate and token to true. #if #dimensions(two) #error "May not compile in 2 dimensions" #endif #if #dimensions(three) int x, y, z; #endif #unassert dimensions // Set predicate and all tokens to false. }Example
When compiling on PA-RISC 2.0 or later, you can test the compiler's predefined assertions. For example:int void main() { #if #model(lp64) // code for 64-bit processor (+DA2.0W) #else #if #model(ilp32) // code for 32-bit processor #endif }Conditional Compilation (#if, #ifdef, .. #endif)
Conditional compilation directives allow you to delimit portions of code that are compiled only if a condition is true.
- Conditional Compilation Syntax and Description
- Using the defined Operator
- Using the #if Directive
- Using the #ifdef and #ifndef Directives
- Using the #else Directive
- Examples
Conditional Compilation Syntax and Description
Syntax:
conditional-directive ::= #if constant-expression newline #ifdef identifier newline [group] #ifndef identifier newline [group] #else newline [group] #elif constant-expression newline [group] #endifHere, constant-expression may also contain the
definedoperator:
defined identifier defined (identifier)
Description:
You can use#if,#ifdef, or#ifndefto mark the beginning of the block of code that will only be compiled conditionally. An#elsedirective optionally sets aside an alternative group of statements. You mark the end of the block using an#endifdirective.
The following
#ifdirective illustrates the structure of conditional compilation:
#if constant-expression ...(Code that compiles if the expression evaluates to a nonzero value.)
... #else ...(Code that compiles if the expression evaluates to zero.)
... #endifThe constant-expression is like other C++ integral constant expressions except that all arithmetic is carried out in
long intprecision. Also, the expressions cannot use thesizeofoperator, a cast, an enumeration constant, or aconstobject.
Using the defined Operator
You can use the
definedoperator in the#ifdirective to use expressions that evaluate to 0 or 1 within a preprocessor line. This saves you from using nested preprocessing directives.The parentheses around the identifier are optional. Below is an example:
#if defined (MAX) && ! defined (MIN) ...Without using the
definedoperator, you would have to include the following two directives to perform the above example:
#ifdef max #ifndef min
Using the #if Directive
The#ifpreprocessing directive has the form:
#if constant-expressionUse
#ifto test an expression. HP aC++ evaluates the expression in the directive. If the expression evaluates to a nonzero value (TRUE), the code following the directive is included. Otherwise, the expression evaluates to FALSE and HP aC++ ignores the code up to the next#else,#endif, or#elifdirective.All macro identifiers that appear in the constant-expression are replaced by their current replacement lists before the expression is evaluated. All
definedexpressions are replaced with either 1 or 0 depending on their operands.
The #endif Directive
Whichever directive you use to begin the condition (#if,#ifdef, or#ifndef), you must use#endifto end the if section.
Using the #ifdef and #ifndef Directives
The following preprocessing directives test for a definition:
#ifdef identifier #ifndef identifierThey behave like the
#ifdirective, but#ifdefis considered true if the identifier was previously defined using a#definedirective or the-Doption.#ifndefis considered true if the identifier is not yet defined.
Nesting Conditional Compilation Directives
You can nest conditional compilation constructs. Delimit portions of the source program using conditional directives at the same level of nesting, or with a-Doption on the command line.
Using the #else Directive
Use the#elsedirective to specify an alternative section of code to be compiled if the#if,#ifdef, or#ifndefconditions fail. The code after the#elsedirective is included if the code following any of the#ifdirectives is not included.
Using the #elif Directive
The#elifconstant-expression directive tests whether a condition of the previous#if,#ifdef, or#ifndefwas false.#elifhas the same syntax as the#ifdirective and can be used in place of an#elsedirective to specify an alternative set of conditions.
Examples
The following examples show valid combinations of conditional compilation directives:
#ifdef SWITCH // compiled if SWITCH is defined #else // compiled if SWITCH is undefined #endif // end of if #if defined(THING) // compiled if THING is defined #endif // end of if #if A>47 // compiled if A is greater than 47 #else #if A < 20 // compiled if A is less than 20 #else // compiled if A is greater than or equal // to 20 and less than or equal to 47 #endif // end of if, A is less than 20 #endif // end of if, A is greater than 47Following are more examples showing conditional compilation directives:
#if (LARGE_MODEL) #define INT_SIZE 32 // Defined to be 32 bits. #elif defined (PC) && defined (SMALL_MODEL) #define INT_SIZE 16 // Otherwise, if PC and SMALL_MODEL // are defined, INT_SIZE is defined // to be 16 bits. #endif #ifdef DEBUG // If DEBUG is defined, display cout << "table element : \n"; // the table elements. for (i=0; i << MAX_TABLE_SIZE; ++i) cout << i << " " << table[i] << '\n'; #endif
Line Control (#line)
You can cause HP aC++ to set line numbers during compilation from a number specified in a line control directive. (The resulting line numbers appear in error message references, but do not alter the line numbers of the actual source code.)
Syntax:
line-directive ::= #line digit-sequence [filename]
Description:
The
#linepreprocessing directive causes HP aC++ to treat lines following it in the program as if the name of the source file were filename and the current line number were digit-sequence. This serves to control the file name and line number that are given in diagnostic messages. This feature is used primarily by preprocessor programs that generate C++ code. It enables them to force HP aC++ to produce diagnostic messages with respect to the source code that is input to the preprocessor rather than the C++ source code that is output.HP aC++ defines two macros that you can use for error diagnostics. The first is
__LINE__, an integer constant equal to the value of the current line number. The second is__FILE__, a quoted string literal equal to the name of the input source file. You can change__FILE__and__LINE__using#includeor#linedirectives.
Example:
#line 5 "myfile"
Pragma Directive (#pragma)
A
#pragmadirective is an instruction to the compiler. You typically use a pragma to control the actions of the compiler in a particular portion of a program without affecting the program as a whole.
Syntax:
pragma-directive ::= #pragma [token-list]
Description:
The
#pragmadirective is ignored by the preprocessor, and instead is passed on to the HP aC++ compiler. It provides implementation-dependent information to HP aC++ Any pragma that is not recognized by HP aC++ will generate a warning from the compiler.
Example:
#pragma OPTIMIZE ON
For More Information:
- Refer to Pragma Directives for descriptions of pragmas recognized by HP aC++
Error Directive (#error)
Syntax:
error-directive ::= #error [preprocessor tokens]
Description:
The
#errordirective causes a diagnostic message, along with any included token arguments, to be produced by HP aC++
Examples:
// This directive will produce the diagnostic // message "FLAG not defined!". #ifndef FLAG #error "FLAG not defined!" #endif // This directive will produce the diagnostic // message "TABLE_SIZE must be a multiple of 256!". #if TABLE_SIZE % 256 != 0 #error "TABLE_SIZE must be a multiple of 256!" #endif
Warning Directive (#warning)
Syntax:
warning-directive ::= #warning [preprocessor tokens]
Description:
The
#warningdirective causes a diagnostic message, along with any included token arguments, to be produced by HP aC++
Examples:
Trigraph Sequences
Description:
The C++ source code character set is a superset of the ISO 646-1983 Invariant Code Set. To enable you to use only the reduced set, you can use trigraph sequences to represent those characters not in the reduced set. A trigraph sequence is a set of three characters that is replaced by a corresponding single character. The preprocessor replaces all trigraph sequences with the corresponding character. The list below gives the complete list of trigraph sequences and their replacement characters.The following are all the trigraph sequences and their respective replacement characters:
??=is replaced by#??/is replaced by\??' is replaced by^??(is replaced by[??)is replaced by]??!is replaced by|??<is replaced by{??>is replaced by}??-is replaced by~
Examples:
The line below contains the trigraph sequence??=:??=line 5 "myfile"When this line is compiled it becomes:
#line 5 "myfile"