C++ Preprocessor: The Code in the Middle - Inclusion Guards
(Page 5 of 6 )
As your application grows, you will have to organize your code among multiple source and header files. All these sources are compiled into object files, which are linked together into possibly a single executable.
Now that you are using multiple classes, many header files will have to be included into each source file. Sometimes header files will include other header files, and it might be possible that one header file will be included multiple times into a single source file.
Let’s create the ubiquitous Animal class from which we’ll derive a Hippopotamus and a Crocodile. Both classes will have to include the Animal header to be able to derive from Animal. To make things easier for whoever wants to play with a Hippopotamus and/or a Crocodile, we’ll include the Animal class in both respective header files.
Now if you are going to use them together, you’ll be including the Animal header twice. Unless you make sure it is included only once, the compiler will start complaining about multiple definitions. This is why we need inclusion guards:
#ifndef _ANIMAL_H
#define _ANIMAL_H
... // your code goes here
#endif
When the preprocessor tries to include the animal header more than once, it will find that _ANIMAL_H is already defined in its definitions table and skip the header. There is a preprocessor directive that takes care of this for the Microsoft compiler: ‘#pragma once’, but you have to remember that this makes your headers non-portable. So why not stick to inclusion guards instead?
Displaying the Intermediate Form
One of the problems with macros is that it can be very hard to deduce what the state of the preprocessor will be when it reaches a certain directive. If you’ve tried porting STL-port across different platforms, you will know what I am talking about: somewhere at the start a definition is put into the preprocessor’s table, cascading through different header files, down to the point where you are interested to see whether a piece is included in the final source that goes to the compiler or not.
Oh the hairs I would have pulled out of my head if it had not been possible to tell the compiler to show us what it sees. Start a shell and make sure you can use your compiler from the command line. If you are using the Microsoft compiler the following command will dump the output from the preprocessor :
cl /EP myfile.cpp
When you are using gcc it can be as simple as:
gcc –E myfile.cpp
Just invoke the help on the compiler to see which command line argument you’ll need. Remember, as your project grows more complex, you will have to provide the inclusion paths to headers that are not present in the same directory.
Next: Predefined Macros >>
More C++ Articles
More By J. Nakamura