Your preferred C/C++ header policy for big projects? [closed]

When working on a big C/C++ project, do you have some specific rules regarding the #include within source or header files?

For instance, we can imagine to follow one of these two excessive rules:

  1. #include are forbidden in .h files; it is up to each .c file to include all the headers it needs
  2. Each .h file should include all its dependancies, i.e. it should be able to compile alone without any error.

I suppose there is trade-off in between for any project, but what is yours? Do you have more specific rules? Or any link that argues for any of the solutions?


Solution 1:

If you include H-files exclusively into C-files, then including a H-file into a C-file might cause compilation to fail. It might fail because you may have to include 20 other H-files upfront, and even worse, you have to include them in the right order. With a real lot of H-files, this system ends up to be an administrative nightmare in the long run. All you wanted to do was including one H-file and you ended up spending two hours to find out which other H-files in which order you will need to include as well.

If a H-file can only be successfully included into a C-file in case another H-file is included first, then the first H-file should include the second one and so on. That way you can simply include every H-file into every C-file you like without having to fear that this may break compilation. That way you only specify your direct dependencies, yet if these dependencies themselves also have dependencies, its up to them to specify those.

On the other hand, don't include H-files into H-files if that isn't necessary. hashtable.h should only include other header files that are required to use your hashtable implementation. If the implementation itself needs hashing.h, then include it in hashtable.c, not in hashtable.h, as only the implementation needs it, not the code that only would like to use the final hashtable.

Solution 2:

I think both suggested rules are bad. In my part I always apply:

Include only the header files required to compile a file using only what is defined in this header. This means:

  1. All objects present as reference or pointers only should be forward-declared
  2. Include all headers defining functions or objects used in the header itself.

Solution 3:

I would use the rule 2:

All Headers should be self-sufficient, be it by:

  • not using anything defined elsewhere
  • forward declaring symbols defined elsewhere
  • including the headers defining the symbols that can't be forward-declared.

Thus, if you have an empty C/C++ source file, including an header should compile correctly.

Then, in the C/C++ source file, include only what is necessary: If HeaderA forward-declared a symbol defined in HeaderB, and that you use this symbol you'll have to include both... The good news being that if you don't use the forward-declared symbol, then you'll be able to include only HeaderA, and avoid including HeaderB.

Note that playing with templates makes this verification "empty source including your header should compile" somewhat more complicated (and amusing...)