This refers to the enabling or disabling of conditional compilation. It discusses both using integer expressions and preprocessor macros.
Let's say you want some code enabled only when you are debugging. You can do something like this:
#define DEBUGGING 1
#if DEBUGGING
printf( "I'm debugging\n" );
#endif
void function( void ) {
if ( DEBUGGING ) {
printf( "I'm debugging\n" );
}
}
This code will work, i.e. you will get two printed output statements that say, "I'm debugging."
The reason is because in the first block (#if DEBUGGING
), the macro DEBUGGING
is converted to a 1 (the value it was defined to represent), then it is evaluated as an integer expression. In other words, the preprocessor reduces the code to this:
#if 1
printf( "I'm debugging\n" );
#endif
void function( void ) {
if ( 1 ) {
printf( "I'm debugging\n" );
}
}
But now consider the case where the #DEBUGGING
macro is not defined at all.
In that case, the preprocessor will reduce the code to this:
//#define DEBUGGING 1 <-- commented out
#if 0 // <--- DEBUGGING is not a macro-word here, so it is converted to 0
printf( "I'm debugging\n" );
#endif
void function( void ) {
if ( DEBUGGING ) { // <---- look what happened here! *Not* in "#if", so NOT preprocessed to zero!
printf( "I'm debugging\n" );
}
}
Because of the way the C language is defined, the #if
test will reduce any word it doesn't recognize as a macro (e.g. int, sizeof, myVariableName, SOME_OTHER_UNDEFINED_THING) to 0, and no error will be given. The first printf statement just won't be compiled in.
However, the second statement which is using what was a macro in the previous version of the code will NOT get a replacement since there is no longer a DEBUGGING
macro defined. In this case, after the preprocessor run, the compiler will complain about a name it doesn't recognize since it will literally see the word DEBUGGING
and not know what to make of it (it isn't a variable name or keyword, etc.).
That's the first thing the paragraph you quoted says.
The second thing it mentions is that #if
statements will reduce its arguments to the result of a single integer expression. That means you can compile code that looks like this:
#define VERSION 2
#if VERSION > 1
printf( "this code only runs on v2+\n" );
#endif
The preprocessor first replaces the word VERSION with the thing it represents:
#if 2 > 1
...
then the preprocessor evaluates the line as an integer expression. Since 2 is greater than 1 (true), the expression/line reduces to:
#if 1
printf( "this code only runs on v2+\n" );
#endif
Regarding sizeof
(and any other keyword or non-macro word), in #if
statements, all names the preprocessor doesn't recognize are converted to zero. This is so it can handle conditional compilation on macros that aren't there, as shown above when I commented out DEBUGGING
.
So this code, which looks like something you might want to do:
#if sizeof(int) > 2
printf( "This machine has 4+ byte integers\n" );
#endif
Will reduce to this:
#if 0(0) > 2 // sizeof and int are non-macro-words so they get replaced with 0
This is an invalid expression, so the compiler will report an error. Thus you cannot use sizeof
(or any other keyword or variable name) in a preprocessor macro.
If you think about it by separating the C preprocessor from the C compiler this makes sense. The preprocessor doesn't know about regular C keywords, that's not its job. It just parses the tokens it cares about (#if
, etc.) then hands off the post-processed C file to the compiler.