Preprocessing directives function as compiler control lines. They allow you to direct the compiler to perform certain actions on the source file.
Syntax
preprocessor-directive ::= include-directive newline macro-directive newline conditional-directive newline line-directive newline error-directive newline pragma-directive newlineDescription
The preprocessing directives control the following general functions:
Comments in the source file that are not passed through the preprocessor are replaced with a single white-space character.
Examples
include-directive: #include <stdio.h> macro-directive: #define MAC x+y conditional-directive: #ifdef MAC line-directive: #line 5 "myfile" pragma-directive: #pragma INTRINSIC func
You can include the contents of other files within the source file using
the #include directive.
include-directive ::= #include <filename> #include "filename" #include <i>identifier
The #include preprocessing directive causes the compiler to switch its input file so that source is taken from the file named in the include directive. Historically, include files are named:
filename.hIf the file name is enclosed in double quotation marks, the compiler searches your current directory for the specified file. If the file name is enclosed in angle brackets, the "system" directory is searched to find the named file. Refer to Refer to Chapter 10, "HP C/HP-UX Implementation Topics," in the HP C/HP-UX Reference Manual for a detailed description of how the directory is searched.
Files that are included may contain #include directives themselves. The HP C compiler supports a nesting level of at least 35 #include files.
The arguments to the #include directive are subject to macro
replacement before the directive processes them. Error messages produced
by the HP C compiler usually supply the file name the error occurred in
as well as the file relative line number of the error.
#include <stdio.h> #include "myheader" #ifdef MINE #define filename "file1" #else #define filename "file2" #endif #include filename
You can define text substitutions in your source file with C macro definitions.
macro-directive ::= #define identifier [replacement-list] #define identifier ( [identifier-list] ) [replacement-list] #undef identifier replacement-list ::= token replacement-list token
#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 white space 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-lista 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 white space. 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 1The 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. */
| NOTE | __DATE__, __TIME__, and __STDC__ are only defined in ANSI mode. |
Conditional compilation directives allow you to delimit portions of
code that are compiled if a condition is true.
conditional-directive ::= #if' constant-expression newline [group] #ifdef identifier newline [group] #ifndef identifier newline [group] #else newline [group] #elif constant-expression newline [group] #endifHere, constant-expression may also contain the defined operator:
defined identifier defined (identifier)
#if constant-expression . . . /* (Code that compiles if the expression evaluates to a nonzero value.) */ #else . . .
. /* (Code that compiles if the expression evaluates to a zero value.) */ #endifThe constant-expression is like other C integral constant expressions except that all arithmetic is carried out in long int precision. Also, the expressions cannot use the sizeof operator, a cast, or an enumeration constant.
You can use the defined operator in the #if directive 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. For example:
#if defined (MAX) && ! defined (MIN) . . .Without using the defined operator, you would have to include the following two directives to perform the above example:
#ifdef max #ifndef minThe #if preprocessing directive has the form:
#if constant-expressionUse #if to test an expression. The compiler evaluates the expression in the directive. If it is true (a nonzero value), the code following the directive is included. If the expression evaluates to false (a zero value), the compiler ignores the code up to the next #else, #endif, or #elif directive.
All macro identifiers that appear in the constant-expression are replaced by their current replacement lists before the expression is evaluated. All defined expressions are replaced with either 1 or 0 depending on their operands.
Whichever directive you use to begin the condition (#if, #ifdef, or #ifndef), you must use #endif to end the if-section.
The following preprocessing directives are used to test for a definition:
#ifdef identifier #ifndef identifierThey behave like the #if directive but #ifdef is considered true if the identifier was previously defined using a #define directive or the -D option. #ifndef is considered true if the identifier is not yet defined.
You can nest these constructions. Delimit portions of the source program using conditional directives at the same level of nesting, or with a -D option on the command line.
Use the #else directive to specify an alternative section of code to be compiled if the #if, #ifdef, or #ifndef conditions fail. The code after the #else directive is compiled if the code following any of the if directives does not compile.
The #elifconstant-expression directive tests whether
a condition of the previous #if,
#ifdef, or #ifndef
was false. #elif is syntactically the same as the #if
directive and can be used in place of an #else directive.
#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 evaluates > 47 */ #else #if A<20 /* compiled if A evaluates < 20 */ #else /* compiled if A >= 20 and <= 47 */ #endif /* end of if, A < 20 */ #endif /* end of if, A > 47 */Examples
#ifdef (HP9000_S800) /* If HP9000_S800 is defined, INT_SIZE */ #define INT_SIZE 32 /* is defined to be 32 (bits) */ #elif defined (HPVECTRA) && defined (SMALL_MODEL) #define INT_SIZE 16 /* Otherwise, if HPVECTRA and */ #endif /* SMALL_MODEL are defined,INT_SIZE is */
#ifdef DEBUG /* If DEBUG is defined, display the */
printf("table element : \n"); /* table elements.*/
for (i=0; i < MAX_TABLE_SIZE; ++i)
printf("%d %f\n", i, table[i]);
#endif
You can cause the compiler to increment 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.)
line-directive ::= #line digit-sequence [filename]
HP C 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. Note that you can change
__FILE__ and __LINE__ using #include or #line
directives.
#line digit-sequence [filename]: #line 5 "myfile"
You can provide instructions to the compiler through inclusion of pragmas.
pragma-directive ::= #pragma replacement-list
#pragma replacement-list: #pragma intrinsic func
_Pragma is a preprocessing unary operator.
_Pragma (string-literal)The string literal is destringized by deleting the L prefix, if present. It deletes the leading and trailing double quotes, replacing each escape sequence by a double-quote, and replacing the escape sequence by a single backlash. The resulting sequence of characters is processed to produce preprocessor tokens that are executed as if they were preprocessed tokens in a pragma directive.
| NOTE | _Pragma is supported only in ANSI (-Aa) and ANSI extended (-Ae) mode. |
_Pragma operator provides portability in the use of an already existing #pragma C preprocessor construct. These #pragmas are processed as defined in its implementation. Most of C implementations provide #pragmas which are very similar in meaning and functionality. The _Pragma operator can be used in the replacement text of a macro, so as to aid in abstracting these specific #pragmas a level higher, thus ensuring their specification in a portable manner.
#pragma listing on "..\listing.dir"can also be expressed as,
_Pragma (listing on \"..\\listing.dir\"")The latter form is processed in the same way whether it appears literally as shown, or it results from macro replacement, as in:
# define LISTING(x) PRAGMA(listing on #x) # define PRAGMA(x) _Pragma(#x) LISTING (..\listing.dir)
_Pragma("HPALIGN 4")
expands to
#pragma HPALIGN 4
#define FOO "HPALIGN 4" _Pragma(FOO)expands to
#pragma HPALIGN 4
#error [pp-tokens]The #error directive causes a diagnostic message, along with any included token arguments, to be produced by the compiler.
#ifndef (HP_C) #error "HP_C not defined!" /* This directive will produce /* the diagnostic message "HP_C /* not defined!"*/ #endif #if TABLE_SIZE % 256 != 0 #error "TABLE_SIZE must be a multiple of 256!" #endif /* This directive will produce /* the diagnostic message /* "TABLE_SIZE must be a /* multiple of 256! */
| NOTE | The #error directive is only supported in ANSI mode. |