Sunteți pe pagina 1din 3

20.

2 Nested Header Files


20.2 Nested Header Files
Suppose you have written a little set of functions which you expect that other parts of your program (or
other parts of other people's programs) will call. And, so that it will be easier for you (and them) to call
the functions correctly, suppose that you have written a header file containing external prototype
declarations for the functions. And, suppose that the prototypes look like this:
extern int f1(int);
extern double f2(int, double);
extern int f3(int, FILE *);
You might put these three declaration in a file called funcs.h.
For now, we don't need to worry about what these three functions might do, other than to notice that f3
obviously reads from or writes to a FILE * stdio stream.
Now, suppose that you have a source file containing a function which calls f1 and/or f2. At the top of
that source file, you would put the line
#include "funcs.h"
However, if you were unlucky, the compiler would get down to the line
extern int f3(int, FILE *);
within funcs.h and complain, because it would not know what a FILE is and so would not know how
to think about a function that accepts a pointer to one. If the calling program (that is, the source file that
included "funcs.h") didn't call f3 or printf or fopen or any of the other stdio functions, it would
have no reason to include <stdio.h>, and FILE would remain undefined. (If, on the other hand, the
source file in question did happen to include <stdio.h>, and if it included it before it included
"funcs.h", there would be no problem.)
What's the right thing to do here? We could say that anyone who included "funcs.h" always had to
include <stdio.h>, first. But you can think of header files a little bit like you think of functions: it's
nice if they're ``black boxes'', if you don't have to worry about what's inside them, if you don't have to
worry about including them in a certain order.
Another way to think about the situation is this: since the prototype for f3 inside of funcs.h needs
stdio.h, maybe we should put the line
http://www.eskimo.com/~scs/cclass/int/sx6b.html (1 of 3)10/31/2005 1:43:57 PM
20.2 Nested Header Files
#include <stdio.h>
right there at the top of funcs.h! Is that legal? Can the preprocessor handle seeing an #include
directive when it's already in the middle of processing another #include directive? The answer is that
yes, it can; header files (that is, #include directives) may be nested. (They may be nested up to a
depth of at least 8, although many compilers probably allow more.) Once funcs.h takes care of its
own needs, by including <stdio.h> itself, the eventual top-level file (that is, the one you compile, the
one that includes "funcs.h") won't get error messages about FILE being undefined, and won't have
to worry about whether it includes <stdio.h> or not.
Or will it? What if the top-level source file does include <stdio.h>? Now <stdio.h> will end up
being processed twice, once when the top-level source file asks for it, and once when funcs.h asks for
it. Will everything work correctly if <stdio.h> is included twice? Again, the answer is yes; the
Standard requires that the standard header files protect themselves against multiple inclusion.
It's good that the standard header files are protected in this way. But how do they protect themselves?
Suppose that we'd like to protect our own header files (such as funcs.h) in the same sort of way. How
would we do it?
Here's the usual trick. We rewrite funcs.h like this:
#ifndef FUNCS_H
#define FUNCS_H
#include <stdio.h>
extern int f1(int);
extern double f2(int, double);
extern int f3(int, FILE *);
#endif
All we've done is added the #ifndef and #define lines at the top, and the #ifndef line at the
bottom. (The macro name FUNCS_H doesn't really mean anything, it's just one we don't and won't use
anywhere else, so we use the convention of having its name mimic the name of the header file we're
protecting.) Now, here's what happens: the first time the compiler processes funcs.h, it comes across
the line
#ifndef FUNCS_H
and FUNCS_H is not defined, so it proceeds. The very next thing it does is #defines the macro
FUNCS_H (with a replacement text of nothing, but that's okay, because we're never going to expand
http://www.eskimo.com/~scs/cclass/int/sx6b.html (2 of 3)10/31/2005 1:43:57 PM
20.2 Nested Header Files
FUNCS_H, just test whether it's defined or not). Then it processes the rest of funcs.h, as usual. But, if
that same run of the compiler ever comes across funcs.h for a second time, when it comes to the first
#ifndef FUNCS_H line again, FUNCS_H will at that point be defined, so the preprocessor will skip
down to the #endif line, which will skip the whole header file. Nothing in the file will be processed a
second time.
(You might wonder what would tend to go wrong if a header file were processed multiple times. It's
okay to issue multiple external declarations for the same function or global variable, as long as they're
all consistent, so those wouldn't cause any problems. And the preprocessor also isn't supposed to
complain if you #define a macro which is already defined, as long as it has the same value, that is, the
same replacement text. But the compiler will complain if you try to define a structure type you've
already defined, or a typedef you've already defined (see section 18.1.6), etc. So the protection against
multiple inclusion is important in the general case.)
When header files are protected against multiple inclusion by the #ifndef trick, then header files can
include other files to get the declarations and definitions they need, and no errors will arise because one
file forgot to (or didn't know that it had to) include one header before another, and no multiple-definition
errors will arise because of multiple inclusion. I recommend this technique.
In closing, though, I might mention that this technique is somewhat controversial. When header files
include other header files, it can be hard to track down the chain of who includes what and who defines
what, if for some reason you need to know. Therefore, some style guides disallow nested header files. (I
don't know how these style guides recommend that you address the issue of having to require that certain
files be included before others.)
Read sequentially: prev next up top
This page by Steve Summit // Copyright 1996-1999 // mail feedback
http://www.eskimo.com/~scs/cclass/int/sx6b.html (3 of 3)10/31/2005 1:43:57 PM

S-ar putea să vă placă și