Including header files style - C++
I have a project which has the following directory structure.
root
--include
----module1
----module2
--src
----module1
----module2
So a file say foo.cpp
in src/module1
has to include like,
#开发者_如何学Goinclude "../../include/module1/foo.hpp"
This looks messy and tough to write. I found writing include like
#include <module1/foo.h>
and providing include file search path to root/include
when compiling looks neat. However, I am not sure that this style has got any drawbacks.
Which one do you prefer and why? Also do you see any problems in organizing files in the above way?
#include "../../include/module1/foo.hpp"
Specifying paths should be avoided as much as possible. Compilers provide you with a cleaner alternative to achieve the same. Further, a clean design should see to it that you do not need to juggle relative paths for including headers.
A better idea of which one to use (including whether to use quotes or the angle-brackets) can be had from the standard.
From my copy of the C++ draft:
16.2 Source file inclusion
2 A preprocessing directive of the form
#include <h-char-sequence> new-line`
searches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the
<
and>
delimiters, and causes the replacement of that directive by the entire contents of the header. How the places are specified or the header identified is implementation-defined.3 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. The named source file is searched for in an implementation-defined manner. If this search is not supported, or if the search fails, the directive is reprocessed as if it read
#include <h-char-sequence> new-line`
with the identical contained sequence (including > characters, if any) from the original directive.
7 Although an implementation may provide a mechanism for making arbitrary source files available to the < > search, in general programmers should use the < > form for headers provided with the implementation, and the " " form for sources outside the control of the implementation.
I support both styles... for different uses
Let's suppose you also have a directory root/src/common
for the purpose of my example
// in src/module1/foo.cpp
#include "module1/foo.h"
#include "../common/stringProcessing.h"
Include
I prefer not to see the 'include' directory, as said of course it is thus more difficult to locate the exact header file... but when you begin and move toward multiple independent libraries you NEED to abstract because you want to be able to move the various components around without altering the code, and I am all for consistency.
Also, there is always the risk using '..' that it does not go where you thought because of a symbolic link traversed backward :/
Source
Sometimes you have headers that are not public, and thus not in the include
directory. These are usually for implementation details that are not relevant for your clients. For those I use the ..
if need be and precise the exact location.
This allows:
- not to clutter the -I
with all possible directories of src
- locate easily the file among your sources
- easily test for dependencies among your sources (grep for ..
)
Misc
If I have to type
#include "module/foo.h"
Then I expect to use:
module::Foo myClass;
which makes it easy to match one particular type to one particular module.
The requirement one library - one namespace, with identical names, makes it easy to navigate the some ~300 or ~400 components we have at work: we HAD to work out some way to organize them!
This means though that your initial layout is reworked as (for the module
project):
root
-- include
---- module
------ part1
------ part2
-- src
---- part1
---- part2
And you then use the following directive: -I/path../root/include
And I expect you to create either a libmodule.so
library or a module
binary.
I much prefer the 2nd way
#include <module1/foo.h>
I find it makes the source much easier to look at. The problem is, when other people come look at your code its not necessarily inherent where the header file is located whereas the first way of including is.
Every style has some drawbacks, but I prefer the one you specified. The include path must not contain any upward relativity (such as ../..
) and must specify the module it relies on.
As a small refinement, I suggest you allow cc
files in module1 to access their .h
files directly:
module1/%.cc: -I $ROOT/includes/module1
or similar. This will create a visual effect in your c files that distinguishes foreign includes from the default include:
// module1/abc.cc
#include <abc.h>
#include <module2/def.h>
Google's C++ style guide has a section on this where they discuss ordering and naming of includes. It basically agrees with what has been said in the other answers so far, but is worth having a look as it is very specific.
I prefer (and Google agrees) to not have relative paths using .. in the include directives. Your initial assessment that it looks neat is correct. Having long, clunky, relative paths makes things harder to read and harder to refactor. I think your approach is correct.
As far as separating source and include files into two different sub-trees: why not have the headers live next to the source files? It makes it easier to match them. Unless you expect other projects to be using your headers and just linking to your binaries, I guess.
<shrug/>
I don't use paths in #include
directives. In my experience, they always cause problems in the maintenance phase. Many compilers allow you to specify search tree for header files.
Files Can Move
They will. Your hierarchy will change. You may want to put the files on a different drive. They may change location when another user modifies your code. The files may move when they are ported for another project. There is nothing preventing your files from moving.
Moving Files Without Modifying Them
Knowing that files will move, if the path is in the file, the file must be modified when it is moved. Without the path in the file, only the build instructions need to change. With large projects, modifying many files is a pain (even with scripts).
In my opinion, paths in #include
directives are evil. People who do this should be retrained or sent to other companies.
精彩评论