Conditional Compilation
Conditional compilation enables you to control the execution of preprocessor directives and the compilation of program code. Each of the conditional preprocessor directives evaluates a constant integer expression. Cast expressions, sizeof expressions, and enumeration constants cannot be evaluated in preprocessor directives. The conditional preprocessor construct is much like the if selection statement.
Consider the following preprocessor code:
#if !defined(MY_CONSTANT)
#define MY_CONSTANT 0
#endif
These directives determine if MY_CONSTANT is defined. The expression defined(MY_CONSTANT) evaluates to 1 if MY_CONSTANT is defined; 0 otherwise. If the result is 0, !defined(MY_CONSTANT) evaluates to 1 and MY_CONSTANT is defined. Otherwise, the #define directive is skipped. Every #if construct ends with #endif. Directives #ifdef and #ifndef are shorthand for #if defined(name) and #if !defined(name).
A multiple-part conditional preprocessor construct may be tested by using the #elif (the equivalent of else if in an if statement) and the #else (the equivalent of else in an if statement) directives.
These directives are frequently used to prevent header files from being included multiple times in the same source file.
Conditional compilation is commonly used as a debugging aid. Many C implementations provide debuggers, which provide much more powerful features than a conditional compilation. If a debugger is not available, printf statements are often used to print variable values and to confirm the flow of control. These printf statements can be enclosed in conditional preprocessor directives so the statements are only compiled while the debugging process is not completed.
For example,
#ifdef DEBUG
printf( "Variable x = %d\n", x );
#endif
causes a printf statement to be compiled in the program if the symbolic constant DEBUG has been defined (#define DEBUG) before directive #ifdef DEBUG. When debugging is completed, the #define directive is removed from the source file (or commented out) and the printf statements inserted for debugging purposes are ignored during compilation. In larger programs, it may be desirable to define several different symbolic constants that control the conditional compilation in separate sections of the source file.
Inserting conditionally compiled printf statements for debugging purposes in locations where C currently expects a single statement. In this case, the conditionally compiled statement should be enclosed in a compound statement. Thus, when the program is compiled with debugging statements, the flow of control of the program is not altered.
#error and #pragma Preprocessor Directives
The #error directive
#error tokens
prints an implementation-dependent message including the tokens specified in the directive. The tokens are sequences of characters separated by spaces.
For example,
#error 1 - Out of range error
contains 6 tokens. When a #error directive is processed on some systems, the tokens in the directive are displayed as an error message, preprocessing stops and the program does not compile.
The #pragma directive
#pragma tokens
causes an implementation-defined action. A pragma not recognized by the implementation is ignored.
# and ## Operators
The # and ## preprocessor operators are available in Standard C. The # operator causes a replacement text token to be converted to a string surrounded by quotes. Consider the following macro definition:
#define HELLO(x) printf( "Hello, " #x "\n" );
When HELLO(John) appears in a program file, it is expanded to
printf( "Hello, " "John" "\n" );
The # operator must be used in a macro with arguments because the operand of # refers to an argument of the macro.
The ## operator concatenates two tokens.
Consider the following macro definition:
#define TOKENCONCAT(x, y) x ## y
When TOKENCONCAT appears in the program, its arguments are concatenated and used to replace the macro. For example, TOKENCONCAT(O, K) is replaced by OK in the program. The ## operator must have two operands.
Line Numbers
The #line preprocessor directive causes the subsequent source code lines to be renumbered starting with the specified constant integer value. The directive #line 100 starts line numbering from 100 beginning with the next source code line.
A file name can be included in the #line directive. The directive #line 100 "file1.c" indicates that lines are numbered from 100 beginning with the next source code line and that the name of the file for the purpose of any compiler messages is "file1.c".
The directive normally is used to help make the messages produced by syntax errors and compiler warnings more meaningful. The line numbers do not appear in the source file.