40

I know that it is common in C/C++ projects to place header files in a directory such as include and implementation in a separate directory such as src. I have been toying with different project structures and am wondering whether there any objective reasons for this or is it simply convention?

Doug Moore
  • 1,028
  • 2
  • 10
  • 20
  • 1
    this might explain it a bit: http://stackoverflow.com/questions/1398445/directory-structure-for-c-library – default Dec 20 '12 at 07:38
  • or maybe this: http://stackoverflow.com/questions/2360734/whats-a-good-directory-structure-for-larger-c-projects-using-makefile – default Dec 20 '12 at 07:39
  • 1
    I once had three places for a math library project: src/ for .c, include/ for internal .h, and api/ for the .h meant for outside use, for apps using the library. I even tried distinguishing the public-facing API headers by naming them .api, but that confused the toolchain. – DarenW Dec 20 '12 at 07:41
  • this is for `c` but might help anyway: http://stackoverflow.com/questions/1451086/folder-structure-for-a-c-project – default Dec 20 '12 at 07:42

5 Answers5

39

Convention is one of the reasons - most of the time, with effective abstraction, you only care about the interface and want to have it easy just looking at the headers.

It's not the only reason though. If your project is organised in modules, you most likely have to include some headers in different modules, and you want your include directory to be cleaned of other "noise" files in there.

Also, if you plan on redistributing your module, you probably want to hide implementation details. So you only supply headers and binaries - and distributing headers from a single folder with nothing else in it is simpler.

There's also an alternative which I actually prefer - public headers go in a separate folder (these contain the minimum interface - no implementation details are visible whatsoever), and private headers and implementation files are separate (possibly, but not necessarily, in separate folders).

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
20

I prefer putting them into the same directory. Reason:

The interface specification file(s), and the source file(s) implementing that interface belongs to the same part of the project. Say you have subsystemx. Then, if you put subsystemx files in the subsystemx directory, subsustemx is self-contained.

If there are many include files, sure you could do subsystemx/include and subsystemx/source, but then I argue that if you put the definition of class Foo in foo.hpp, and foo.cpp you certainly want to see both of them (or at least have the possibility to do so easily) together in a directory listing. Finding all files related to foo

ls foo*

Finding all implementation files:

ls *.cpp

Finding all declaration files:

ls *.hpp

Simple and clean.

user877329
  • 6,717
  • 8
  • 46
  • 88
  • 4
    But code outside of subsystemx needs to use the public interfaces — so the public interface headers need to be accessible simply and under control. Can you imagine the mess if you had to guess which of the headers for subsystemx were for internal use only and which are for extenal use — which define the API? The private headers can live alongside the source code no problem. But the public headers that consumers need — those need to be made available in a more controlled fashion. – Jonathan Leffler Jun 24 '16 at 14:16
  • 3
    @JonathanLeffler I design so there are no private headers. It always makes sense to `#include "subsystemx/foo.hpp"`. If there are internal details, I hide them inside the implementation file(s). Also, how do you decide that a header is for private use only? – user877329 Jun 24 '16 at 14:23
  • 3
    You're lucky to work on such small systems. – Jonathan Leffler Jun 24 '16 at 14:24
  • 2
    @JonathanLeffler Also if you need private headers, add a suffix `_internal` can be added to the filename. – user877329 Sep 11 '16 at 08:09
  • 2
    I agree with this approach. There are tools (such as autotools) that distribute your project, the install make target will figure out what to install into the PREFIX. – Kemin Zhou Dec 09 '16 at 01:04
  • @JonathanLeffler is correct. For any sizeable project, in order to build, package etc. it, it is advantageous to separate "public" files and "private" files. For instance, for a library subsystem, the public view can be "inc" dir with headers and "lib" dir with binary. All implementation (source + internal headers) can be placed in "src". "Src" is not visible to clients of the subsystem. It is only used by the build system when it makes the binary. The build system can also enforce the fact that "src" is hidden from clients -- add "inc" to preprocessor and "lib" to linker paths. – Petr Vepřek Oct 20 '17 at 09:59
  • QT for example uses this approach: https://github.com/qt/qtbase/tree/dev/src/network/socket – Gabriel Aug 25 '21 at 21:01
8

It keeps your folder structure cleaner. Headers and source files are distinctly different, and are used for different things, so it makes sense to separate them. From this point-of-view the question is basically the same as "why do source files and documentation go in different folders"? The computer is highly agnostic about what you put in folders and what you don't, folders are -- for the most part -- just a handy abstraction because of the way that we humans parse, store, and recall information.

There's also the fact that header files remain useful even after you've built, i.e. if you're building a library and someone wants to use that library, they'll need the header files -- not the source files -- so it makes bundling those header files up -- grabbing the stuff in bin and the stuff in include and not having to sift through src -- much easier.

3

Besides (arguable?) usefulness for keeping things orderly, useful in other projects etc, there is one very neutral and objective advantage: compile time.

In particular, in a big project with a whole bunch of files, depending on search paths for the headers (.c/.cpp files using #include "headername.h" rather than #include "../../gfx/misc/something/headername.h" and the compiler passed the right parameters to be able to swallow that) you drastically reduce the number of entries that need to be scanned by the compiler in search of the right header. Since most compilers start separately for each file compiled, they need to read in the list of files on the include path and seek the right headers for each compiled file. If there is a bunch of .c, .o and other irrelevant files on the include path, finding the includes among them takes proportionally longer.

SF.
  • 13,549
  • 14
  • 71
  • 107
  • 1
    Why would the compiler scan a `.c` file to match a header, it knows the path, it only appends the `#include ` to the given include dirs and checks if a file exists, other files dont interact in this process, therefore I dont understand your point? – Gabriel Aug 25 '21 at 20:55
  • 1
    *and checks if a file exists* - depending on filesystem, checking if a file exists in a directory may vary in complexity between O(log(n)) and O(n) (with some shameful, luckily rare and obsolete exceptions of O(n^2) ) - regardless, the more files in a directory the longer finding a particular file is and while it may take microseconds per file, it's millions of such queries in compilation of a a big project and It adds up. – SF. Aug 25 '21 at 22:50
1

In short, a few reasons:

  • Maintainable code.
  • Code is well-designed and neat.
  • Faster compile time (at times, for minor changes done).
  • Easier segregation of the Interfaces for documentation etc.
  • Cyclic dependency at compile time can be avoided.
  • Easy to review.

Have a look at the article Organizing Code Files in C and C++ which explains it well.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
parasrish
  • 3,864
  • 26
  • 32
  • Can you explain how this separation reduces the risk of cyclic dependencies? – user877329 Jun 24 '16 at 14:11
  • 3
    I'm pretty sure @parasrish was answering a different question "why separate headers into separate *files*" rather than separate directories as the OP asked. – Catskul Aug 15 '16 at 19:02