The C compiler preprocesses every source file before performing the actual translation. The preprocessor removes comments and replaces macros with their definitions.
Every preprocessing directive appears on a line by itself, beginning with the character #. If the directive is long, it can be continued on the next line by inserting a backslash (\) as the last character before the line break.
|
|
|
The #define directive is used to define macros.
define name[(parameter_list)] [replacement_text]
The preprocessor replaces each occurrence of name or name(parameter_list) in the subsequent source code with replacement_text.
#define BUF_SIZE 512 // Symbolic constant
#define MAX(a,b) ((a) > (b) ? (a) : (b))
These directives define the macros BUF_SIZE and MAX. If the replacement text is a constant expression, the macro is also called a symbolic constant. Macros can also be nested; a macro, once defined, can be used in another macro definition.
In the previous example, the parentheses are necessary in order for the substitution to be performed correctly when MAX is used in an expression, or when complex expressions replace the parameters a and b. For example, the preprocessor replaces the macro invocation:
result = 2 * MAX( x, y & 0xFF );
with:
result = 2 * ( (x) > (y & 0xFF) ? (x) : (y & 0xFF) );
|
|
|
In the macro replacement text, the parameters of the macro may be preceded by the operator # (called the hash or stringizing operator). In this case, the preprocessor sets the corresponding argument in quotation marks, thus converting it into a string.
#define print_int(i) printf( "value " #i " = %d", i )
If x and y are variables with type int, then the statement:
print_int(x-y);
is replaced with:
printf( "value ""x-y"" = %d", x-y );
Because consecutive string literals are concatenated, this is equivalent to:
printf( "value x-y = %d", x-y );
|
|
|
If a macro parameter appears in the replacement text preceded or followed by the operator ## (called the double-hash or token-pasting operator), then the preprocessor concatenates the tokens to the left and right of the operator, ignoring any spaces. If the resulting text also contains a macro name, then macro replacement is performed once again.
#define show( var, num ) \
printf( #var #num " = %.1f\n", var ## num )
If the float variable x5 has the value 16.4, then the macro invocation:
show( x, 5 );
is replaced with:
printf( "x" "5" " = %.1f\n", x5 );
// Output: x5 = 16.4\n
|
|
|
The #undef directive cancels a macro definition. This is necessary when the definition of a macro needs to be changed, or when a function of the same name needs to be called.
#undef name
No parameter list needs to be specified, even if the previously defined macro has parameters.
#include <ctype.h>
#undef toupper
. . .
c = toupper(c); // Call the function toupper()
|
|
|
The #include directive instructs the preprocessor to insert the contents of a specified file in the program at the point where the #include directive appears.
#include <filename>
#include "filename"
If the filename is enclosed in angle brackets, the preprocessor only searches for it in certain directories. These directories are usually named in the environment variable INCLUDE.
If the filename is enclosed in quotation marks, the preprocessor first looks for the file in the current working directory.
The filename may contain a directory path. In this case, the file is only looked for in the specified directory.
The files named in include directives are generally "header" files containing declarations and macro definitions for use in several source files, and have names ending in .h. Such files may in turn contain further #include directives.
In the following example, one file to be included is selected based on the value of a symbolic constant:
#include <stdio.h>
#include "project.h"
#if VERSION == 1
#define MYPROJ_H "version1.h"
#else
#define MYPROJ_H "version2.h"
#endif
#include MYPROJ_H
|
|
|
These directives are used to present source code to the compiler only on certain conditions. In this way a different selection of program statements can be compiled from one build to another. This technique can be used to adapt a single program to a variety of target systems, for example, without requiring modification of the source code.
#if expression1
[text1]
[#elif expression2
text2]
. . .
[#elif expression(n)
text(n)]
[#else
text(n+1)]
#endif
Each #if directive may be followed by any number of #elif directives, and at most one #else directive. The conditional source code section must be closed by an #endif directive.
The preprocessor evaluates expression1, expression2, etc. in succession. At the first expression whose value is "true", i. e., not equal to 0, the conditional code is processed. If none of the expressions is true, then the #else directive is processed, if present.
expression1, expression2, etc. must be constant integer expressions. The cast operator cannot be used in preprocessing directives.
The conditional text consists of program code, including other preprocessing directives and ordinary C statements. Conditional text that the preprocessor skips over is effectively removed from the program.
|
|
|
The defined operator can be used to verify whether a given macro name is currently defined.
defined (name)
The operator yields a non-zero value if a valid definition exists for name; otherwise it yields the value 0. A macro name defined by a #define directive remains defined until it is cancelled by an #undef directive. A macro name is considered to be defined even if no replacement text is specified after name in the #define directive.
The defined operator is typically used in #if and #elif directives:
#if defined(VERSION
...
#endif
Unlike the #ifdef and #ifndef directives, the defined operator yields a value that can be used in a preprocessor expression:
#if defined(VERSION) && defined(STATUS
...
#endif
|
|
|
The #ifdef and #ifndef directives can be used to make program text directly conditional upon whether a given macro name is defined.
#ifdef name
#ifndef name
The #ifdef directive is "true" if name is defined, and the #ifndef directive is "true" if name is not defined. Both require a closing #endif directive.
The following two constructions are equivalent:
#ifdef VERSION
...
#endif
#if defined(VERSION
...
#endif
|
|
|
The compiler identifies errors it encounters during compilation by the source filename and the line number in the file. The #line directive can be used to change the filename and line numbering in the source file itself.
#line new_number ["filename"]
From this location in the file onward, lines are counted starting from new_number. If filename is also specified, it becomes the new filename indicated by the compiler in any error messages.
The new filename must be enclosed in quotation marks, and new_number must be an integer constant.
#line 500 "my_prg.c"
The #line directive is typically used by program generators in translating other kinds of code into a C program. In this way the C compiler's error messages can be made to refer to the appropriate line and filename in the original source code.
The current effective line number and filename are accessible through the predefined macros _ _LINE_ _ and _ _FILE_ _.
printf( "Current source line number: %d\n", _ _LINE_ _ );
printf ( "Source file: %s\n", _ _FILE_ _ );
|
|
|
The #pragma directive is implementation-specific. It can be used to define any preprocessor directives desired for a given compiler.
#pragma command
Any compiler that does not recognize command simply ignores the #pragma directive.
#pragma pack(1)
The Microsoft C compiler interprets this directive as an instruction to align the members of structures on byte boundaries, so that no unnamed gaps occur. (Other pragmas supported by that compiler are pack(2) and pack(4), for word and double-word alignment.)
ANSI C99 introduces the standard pragmas CX_LIMITED_RANGE, FENV_ACCESS, and FP_CONTRACT, which are described in the upcoming section Section 1.18.
There are eight predefined macros in C, whose names begin and end with two underline characters. They are described in Table 1-21.
ANSI C99 distinguishes between "hosted" and "free-standing" execution environments for C programs. Unlike the normal "hosted" environment, a "freestanding" environment provides only the capabilities of the standard library as declared in the header files float.h, iso646.h, limits.h, stdarg.h, stdbool.h, and stddef.h.