C++/#ifndef preprocessor
Expert: Ralph McArdell - 3/24/2008
Question
Hello, Mr McArdell
I have the following question
I've been trying to use the #ifndef, #define and #endif preprocessors to avoid multiple file inclusions
How do I do this??
Could you provide a simple example?
Thanks
P.S. I've been looking in c++ books and on the net for this
but there is not much information on this topic. I wonder if it's because it's uncommon practice or an old code syntax...
AnswerThe technique you refer to is called include guards. In fact to be specific it is internal include guards, rather than external include guards because the guard against multiple inclusion of the body of a header file is included internally to that header file. There is a related technique of external include guards whereby the including files provide guards against multiple header file inclusion, however this involves more work and maintenance, and was mooted as possibly useful for huge projects to reduce compile times by stopping the compiler from even starting to process header files more than once.
The technique is not uncommon - far from it, nor is it old syntax, although some compilers provide specific support for header file single inclusion, the Microsoft Visual C++ compilers for example have a #pragma once directive that can be placed at the start of a header file. The problem with facilities like #pragma once is that they are non-standard and therefore not portable between compilers.
The idea is this:
The first time a header file is included we define a uniquely named macro, and process the body of the header file.
Subsequent inclusions will not process the body of the header as this macro is defined.
Thus we get:
If macro not defined:
define macro
process header body
End If
If you check almost any library header file intended for compilers without specific support for header file single inclusion you are likely to come across examples, although there are some exceptions where multiple inclusion is intended it is not the norm.
Here is an outline:
// Header file outline
#ifndef HEADER_FILE_GUARD_MACRO
# define HEADER_FILE_GUARD_MACRO
// body of header file
#endif // ifndef HEADER_FILE_GUARD_MACRO
Note that the name of the macro, HEADER_FILE_GUARD_MACRO in this case, has to be unique (at least within the scope of the header file's usage) and therefore different for every header file. I have seen several schemes used to help ensure this, for example using date and time in the name or using a UUID/ GUID value in the name. I currently use the name of my company, the project name, names of each namespace in the namespace 'path' the items in the header file are members of and the name of the header file all converted to upper case and spaces, dots etc. replaced by underscores. Here are some real life examples:
1/ From a wizard generated MFC project stdafx.h file from an older Microsoft Visual C++ IDE, which uses a UUID value in the guard macro name (newer such header files just use #pragma once):
#if !defined(AFX_STDAFX_H__360AB1F7_8C5F_11D5_BDDB_009027889720__INCLUDED_)
#define AFX_STDAFX_H__360AB1F7_8C5F_11D5_BDDB_009027889720__INCLUDED_
// Header body ...
#endif // !defined(AFX_STDAFX_H__360AB1F7_8C5F_11D5_BDDB_009027889720__INCLUDED_)
Note they prefer the equivalent #if !defined(...) to #ifndef and use double underscores, which, alas, we as mere users of C++ are not allowed to do. Such usages are reserved for implementers.
2/ Date and time example. I had to make this one up as I did not have an actual example to hand:
#ifndef HEADER_2008_03_24_12_49_VECTOR_H
# define HEADER_2008_03_24_12_49_VECTOR_H
// Header body ...
#endif
3/ Long name using hopefully unique company, project and namespace details:
#ifndef DIBASE_SVNFIXUP_RESOURCE_TYPES_H
# define DIBASE_SVNFIXUP_RESOURCE_TYPES_H
// Header body ...
#endif // ifndef DIBASE_SVNFIXUP_RESOURCE_TYPES_H
and:
#ifndef DIBASE_SVNFIXUP_COMMANDLINE_TYPES_H
# define DIBASE_SVNFIXUP_COMMANDLINE_TYPES_H
// Header body ...
#endif // ifndef DIBASE_SVNFIXUP_COMMANDLINE_TYPES_H
As you can see my project has more than one types.h header for types used for different modules, which have their own namespace. To keep them separate each module's headers are kept in a their own directory (named similarly to the module's namespace) below the main project include directory.
Finally, one thing I should mention is that if you are getting very weird errors from compiling source files that include a new header file that you created by copying and modifying an existing header file then check you updated the name of the include guard macro in the new header file. The errors would imply the compiler has no knowledge of the definitions and declarations in either the new header file or the one you copied it from initially, depending on which was included first. I speak from experience!
There is a Wikipedia article on include guards at
http://en.wikipedia.org/wiki/Include_guard
Hope this has clarified the technique for you.