Conditional Compilation:
A
preprocessor conditional compilation directive causes the preprocessor to conditionally suppress the compilation of portions of source code. These directives test a constant expression or an identifier to determine which tokens the preprocessor should pass on to the compiler and which tokens should be bypassed during preprocessing. The directives are:
- #if
- #ifdef
- #else
- #ifndef
- #elif
- #endif
The preprocessor conditional compilation directive spans several lines:
- The condition specification line (beginning with #if, #ifdef, or #ifndef)
- Lines containing code that the preprocessor passes on to the compiler if the condition evaluates to a nonzero value (optional)
- The #elif line (optional)
- Lines containing code that the preprocessor passes on to the compiler if the condition evaluates to a nonzero value (optional)
- The #else line (optional)
- Lines containing code that the preprocessor passes on to the compiler if the condition evaluates to zero (optional)
- The preprocessor #endif directive
For each
#if,
#ifdef, and
#ifndef directive, there are zero or more
#elif directives, zero or one
#else directive, and one matching
#endif directive. All the matching directives are considered to be at the same nesting level.
You can nest conditional compilation directives. In the following directives, the first
#else is matched with the
#if directive.
#ifdef MACNAME
/* tokens added if MACNAME is defined */
# if TEST <=10
/* tokens added if MACNAME is defined and TEST <= 10 */
# else
/* tokens added if MACNAME is defined and TEST > 10 */
# endif
#else
/* tokens added if MACNAME is not defined */
#endif
Each directive controls the block immediately following it. A block consists of all the tokens starting on the line following the directive and ending at the next conditional compilation directive at the same nesting level.
Each directive is processed in the order in which it is encountered. If an expression evaluates to zero, the block following the directive is ignored.
When a block following a preprocessor directive is to be ignored, the tokens are examined only to identify preprocessor directives within that block so that the conditional nesting level can be determined. All tokens other than the name of the directive are ignored.
Only the first block whose expression is nonzero is processed. The remaining blocks at that nesting level are ignored. If none of the blocks at that nesting level has been processed and there is a
#else directive, the block following the
#else directive is processed. If none of the blocks at that nesting level has been processed and there is no
#else directive, the entire nesting level is ignored.
#warning:
A
preprocessor warning directive causes the preprocessor to generate a warning message but allows compilation to continue. The argument to
#warning is not subject to macro expansion.
#error:
The directive ‘
#error’ causes the preprocessor to report a fatal error. The tokens forming the rest of the line following ‘
#error’ are used as the error message.
You would use ‘
#error’ inside of a conditional that detects a combination of parameters which you know the program does not properly support. For example, if you know that the program will not run properly on a VAX, you might write
#ifdef __vax__
#error "Won't work on VAXen. See comments at get_last_object."
#endif
If you have several configuration parameters that must be set up by the installation in a consistent way, you can use conditionals to detect an inconsistency and report it with ‘
#error’. For example,
#if !defined(FOO) && defined(BAR)
#error "BAR requires FOO."
#endif
The directive ‘
#warning’ is like ‘
#error’, but causes the preprocessor to issue a warning and continue preprocessing. The tokens following ‘
#warning’ are used as the warning message.
You might use ‘
#warning’ in obsolete header files, with a message directing the user to the header file which should be used instead.
Neither ‘
#error’ nor ‘
#warning’ macro-expands its argument. Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this avoids problems with apostrophes and the like.
Notes:* -
#ifdef identifier is the same is #if defined( identifier).#ifndef identifier is the same as #if !defined(identifier).
Predefined Macros
The following macros are already defined by the compiler and cannot be changed.
| __LINE__ | A decimal constant representing the current line number. |
| __FILE__ | A string representing the current name of the source code file. |
| __DATE__ | A string representing the current date when compiling began for the current source file. It is in the format "mmm dd yyyy", the same as what is generated by the asctime function. |
| __TIME__ | A string literal representing the current time when cimpiling began for the current source file. It is in the format "hh:mm:ss", the same as what is generated by the asctime function. |
| __STDC__ | The decimal constant 1. Used to indicate if this is a standard C compiler. |