Dreaming in Code Dreaming in Code - 1 year ago 68
C Question

Cross-file #if and #endif - should it be legal?

According to the C11 standard,

A preprocessing directive of the form

# include "q-char-sequence" new-line

causes the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters.

So if I have a header file


And a source file

#if 1
#include "test.h"

Shouldn't it pass the preprocessing phase according to the standard by replacing the content of
in place?

But I cannot do this with
, which says:

In file included from test.c:2:
./test.h:1:2: error: #endif without #if
test.c:1:2: error: unterminated conditional directive
#if 1
2 errors generated.

So what is the behavior that the standard specified?

Answer Source

If you read e.g. this C++ #include reference the included file is first run through translation phases one to four, and phase four is running the preprocessor (recursively).

That means the file you include must be complete in regards to #if and #endif.

This happens in C as well.

After reading the C11 specification (ISO/IEC 9899:2011 [2012]) what I think happens is this:

The compiler is in the preprocessor phase (phase 4) and evaluates the #if 1 preprocessor directive. The condition evaluates to true, so it enters the block inside the condition. There is sees the #include "test.h" directive.

When the compiler processes an include directive it temporarily stops processing the current file, to process the included file. This processing of the included file goes through compilation phase 1 through 4 (inclusive) before continuing with the current source file.

When the processing of the included header file itself comes to phase 4 and starts to process the #endif directive, then it doesn't go up in the recursive stack to find the matching #if, the preprocessor only looks at the current frame. Therefore you get the first error about no #if. The standard doesn't actually say anything about this. All it says, basically, is that an #if must have a matching #endif. That the compiler doesn't go up the inclusion stack to find the matching #if seems to be more an implementation detail.

Anyway, the preprocessor ends its processing of the header file with step 3 in phase 4, which is

At the end of this phase, all preprocessor directives are removed from the source.

So when the control comes back to the preprocessing for the source file, the file it actually includes doesn't contain any preprocessing directives. Al that is included is an empty file, basically. And this leads to the second error, that there is no #endif for the #if, because there really isn't.