92

What things should absolutely always/never be included in a header file?

  • Functions: what must go in the header file and what mustn't
  • Constants: Is it good practice to define lot of constants in a header file?
  • Any other good practices for C header files?

Example

I'm writing a parser for a documented industry standard format that has a lots of constants, is it a good practice to define them in a header file?

3
  • 1
    Short and painless: definitions and declartions that are needed in more than one module.
    – ott--
    Oct 6, 2012 at 20:51
  • 36
    Marking this question as "too broad" and closing is an absolute shamefull overkill of moderation. This question exactly asks what i am looking for - the Question is well formed and does ask a very clear question: what are the best practices? If this is "too broad" for softwareengineering .. we could aswell just close down this whole forum.
    – Gewure
    Feb 21, 2017 at 10:35
  • TL; DR. For C++, in the fourth edition of "The C++ Programming Language" written by Bjarne Stroustrup (its creator), in Section 15.2.2 it is described what a header should and should not contain. I know you tagged the question to C, but some of the advices are also applicable. I think this is a good question...
    – horro
    Mar 14, 2018 at 10:07

5 Answers 5

76

What to put in headers:

  • The minimal set of #include directives that are needed to make the header compilable when the header is included in some source file.
  • Preprocessor symbol definitions of things that need to be shared and that can only accomplished via the preprocessor. Even in C, preprocessor symbols are best kept to a minimum.
  • Forward declarations of structures that are needed to make the structure definitions, function prototypes, and global variable declarations in the body of the header compilable.
  • Definitions of data structures and enumerations that are shared amongst multiple source files.
  • Declarations for functions and variables whose definitions will be visible to the linker.
  • Inline function definitions, but take care here.

What doesn't belong in a header:

  • Gratuitous #include directives. Those gratuitous includes cause recompilation of things that don't need to be recompiled, and can at times make it so a system can't compile. Don't #include a file in a header if the header itself doesn't need that other header file.
  • Preprocessor symbols whose intent could be accomplished by some mechanism, any mechanism, other than the preprocessor.
  • Lots and lots of structure definitions. Split those up into separate headers.
  • Inline definitions of functions that require an additional #include, that are subject to change, or that are too big. Those inline functions should have little if any fan out, and if they do have fan out, it should be localized to stuff defined in the header.

What constitutes the minimal set of #include statements?

This turns out to be a nontrivial question. A TL;DR definition: A header file must include the header files that directly define each of the types directly used in or that directly declare each of the functions used in the header file in question, but must not include anything else. A pointer or C++ reference type does not qualify as direct use; forward references are preferred.

There is a place for a gratuitous #include directive, and this is in an automated test. For every header file in a software package, I automatically generate and then compile the following:

#include "path/to/random/header_under_test"
int main () { return 0; }

The compilation should be clean (i.e., free of any warnings or errors). Warnings or errors regarding incomplete types or unknown types mean that the header file under test has some missing #include directives and/or missing forward declarations. Note well: Just because the test passes does not mean that the set of #include directives is sufficient, let alone minimal.


Related

9
  • So, if I have a library that defines a struct, called A, and this library, called B, uses that struct, and library B is used by program C, should I include library A's header file in library B's main header, or should I just forward declare it? library A is compiled and linked with library B during it's compilation.
    – MarcusJ
    Jul 11, 2018 at 14:34
  • @MarcusJ - The very first thing I listed under What doesn't belong in a header was gratuitous #include statements. If header file B does not depend on the definitions in header file A, don't #include header file A in header file B. A header file is not the place to specify third party dependencies or build instructions. Those go somewhere else such as a top-level readme file. Jul 12, 2018 at 3:24
  • 1
    @MarcusJ - I updated my answer in an attempt to answer your question. Note that there isn't one answer to your question. I'll illustrate with a couple of extremes. Case 1: The only place where library B directly uses the functionality of library A is in the library B source files. Case 2: Library B is a thin extension of the functionality in library A, with the header file(s) for library B directly using types and/or functions defined in library A. In case 1, there's no reason to expose library A in the header(s) for library B. In case 2, this exposure is pretty much mandatory. Jul 13, 2018 at 20:55
  • Yeah it's case 2, sorry my comment skipped over the fact that it's using types declared in library A in library B's headers, I was thinking I might be able to forward declare it, but I don't think that's gonna work. Thanks for the update.
    – MarcusJ
    Jul 14, 2018 at 22:15
  • Is adding constants to a header file a big no-no?
    – mding5692
    Nov 17, 2018 at 19:57
20

In addition to what has already been said.

H files should always contain:

  • Source code documentation!!! At a minimum, what is the purpose of the various parameters and return values of the functions.
  • Header guards, #ifndef MYHEADER_H #define MYHEADER_H ... #endif

H files should never contain:

  • Any form of data allocation.
  • Function definitions. Inline functions may be a rare exception in some cases.
  • Anything labelled static.
  • Typedefs, #defines or constants that have no relevance to the rest of the application.

(I would also say that there is never any reason to use non-constant global/extern variables, anywhere, but that's a discussion for another post.)

8
  • 2
    I agree with everything, except what you have highlighted. If you are making a library, yes, you should document or the users of your library. For an in-house project you shouldn't need to clutter your headers with documentation, if you use good, self explanatory variable and function names.
    – martiert
    Oct 8, 2012 at 14:02
  • 5
    @martiert I'm also of the "let the code speak for itself" school. Yet you should at the very least always document your functions, even if nobody but yourself will use them. Things of particular interest are: in case the function has error handling, what error codes does it return and under which conditions does it fail? What happens to parameters (buffers, pointers etc) if the function fails? Another thing that is very relevant is: are the pointer parameters returning something to the caller, ie do they expect allocated memory? ->
    – user29079
    Oct 8, 2012 at 14:09
  • 1
    It should be obvious to the caller what error handling is done inside the function and what is not done. If the function expects an allocated buffer, it will most likely leave the out-of-bounds checks to the caller as well. If the function relies on another function to be executed, this must be documented (ie run link_list_init() before link_list_add()). And finally, if the function has a "side-effect" such as creating files, threads, timers or whatever, it should be stated in the documentation. ->
    – user29079
    Oct 8, 2012 at 14:12
  • 1
    Maybe "source code documentation" is too broad here, this really belongs to the source code. "Usage documentation" with input and output, pre- and postconditions and side-effects should definitely go there, not in epic but in a brief form.
    – Secure
    Oct 8, 2012 at 14:19
  • 2
    A bit belated, but +1 for documentation. Why does this class exist? The code does not speak for itself. What does this function do? RTFC (read the fine .cpp file) is an obscene four letter acronym. One should never have to RTFC for understanding. The prototype in the header should summarize, in some extractable comment (e.g., doxygen), what the arguments are and what the function does. Why does this data member exist, what does it contain, and is the value in meters, feet, or furlongs? That too is another subject for (extractable) comments exist. Oct 14, 2013 at 12:55
4

Header file should have the following organization:

  • type and constant definitions
  • external object declarations
  • external function declarations

Header files should never contain object definitions, only type definitions and object declarations.

5
  • What about inline function definitions?
    – Kos
    Oct 6, 2012 at 10:00
  • If the inline function is a “helper” function that’s only used inside one C module, then put it in that .c file only. If, the inline function must be visible to two or more modules, the put it inside the header file.
    – theD
    Oct 6, 2012 at 10:16
  • Also, if the function has to be visible across a library boundary, don't make it inline as that forces everyone who uses the library to recompile every time you modify things. Oct 6, 2012 at 12:11
  • @DonalFellows: That's a backhanded solution. A better rule: Don't put stuff in headers that is subject to frequent modification. There's nothing wrong with inlining a short little function in a header if the function has no fanout and has a clear definition that will only change if the underlying data structure changes. If the function definition changes because the underlying structure definition changed, yeah, you have to recompile everything, but your going to have to do that anyway because the structure definition changed. Oct 6, 2012 at 14:11
  • so is constant definition not an object definition? Like const int x = 5; Or are you talking about macros here? Oct 10, 2020 at 19:55
4

I would probably never say never, but statements that generate data and code as they are parsed should not be in a .h file.

Macros, inline functions and templates may look like data or code, but they do not generate code as they are parsed, but instead when they are used. These items often need to be used in more than one .c or .cpp, so they belong in the .h.

In my view, a header file should have the minimum practical interface to a corresponding .c or .cpp. The interface can include #defines, class, typedef, struct definitions, function prototypes, and less preferred, extern definitions for global variables. However, if a declaration is used in only one source file, it probably should be excluded from the .h and be contained in the source file instead.

Some may disagree, but my personal criteria for .h files is that they #include all other .h files that they need to be able to compile. In some cases, this can be a lot of files, so we have some effective methods to reduce external dependencies like forward declarations to classes that let us use pointers to objects of a class without including what could be a big tree of include files.

0

Statements that generate data and code as they are parsed, should not be in a .h file. As far as my point of view is concerned, a header file should only have the minimum practical interface to a corresponding .c or .cpp.

Not the answer you're looking for? Browse other questions tagged or ask your own question.