Programming Techniques:C/CPP Header File Convention

From GPWiki
Jump to: navigation, search

C/C++ Header File Convention

At some point, a person learning to program in C/C++ learns the distinction between "header" files and "source" files. That is, a source file is compiled by the compiler and header files are shared among the source files. Then the question becomes, "How do I use header files effectively?" This is a description of the modern convention for what goes into header files, how header files are organized, and how they are used.

A Short History of Header Files

In the Middle Ages of the Computer Era (that would be the 1980s), the "header" file was born, and it was used to store all the constants and declarations that a "source" file would need. It included internal details and references to external functions (using the evil "extern" keyword). Header files were regarded as the file equivalent of a macro and they were used primarily for convenience.

A typical header file for main.c looked something like this:

/* main.h (included by main.c) circa 1980. Don't do this. */
 
/* Header files needed by main.c */
 
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <math.h>
 
/* External data referenced by main.c */
 
extern char z[128];
 
/* Functions in foo.c that are called by main.c */
 
extern int a( char * );
extern int b( char * );
 
/* Functions defined and used only in main.c */
 
static int x();
static int y();
 
/* Constants used by main.c */
 
#define X		1
#define Y		2

With the birth of Object-Oriented Programming, it was realized that the way header files were being used was backwards, and that it is much better to use a header file as a description of the API for a source file or module. The declarations in the header file describe what constants, types, data, and functions the source file or module provides to its users. This is the convention in common use today.

What Goes in a Header File

As stated above, a header file is used to describe the API for a module or source file. It contains declarations of all the constants, types, data, and functions provided by the module.

Here are the things that go in a header file:

  • include guards,
  • the header files needed to compile the rest of the header file - no more, no less (except in the cases of meta-header files and precompiled header files),
  • forward declarations (preferred to including header files),
  • declarations of constants that are part of what the module provides,
  • declarations of the classes, structs and other types implemented by the source file that are available for use by others (private types should not be declared in the header file),
  • declarations of functions implemented in the source file that are available for use by others,(static functions are not be declared in the header file),
  • declarations of data in the source file that is available for use by others (a.k.a. global data),
  • inline functions and template class implementations.

What Does Not Go in a Header File

In the current convention, exposing internal or private constants, types, data, and functions to the world is wrong. None of the lines in the code example above should be included in a header file.

Here is what does not go in a header file for a module:

  • header files needed only by the associated module or source file,
  • constants, types, data, and function declarations that are private to the module,
  • any other unnecessary implementation details about the module or source file.


Including Header Files In A Source File

The order of inclusion of header files is mostly a matter of preference, with the exception of one requirement and one very useful convention. Here is the preferred order:

  • (optional) Header files needed but already included in the precompiled header file.
    If a precompiled header file is used, all text before the line that includes the precompiled header is ignored. It can be useful to duplicate the headers in case the file is compiled with a dummy precompiled header file file when precompiled header files are turned off. The drawback is that they can be difficult and/or tedious to maintain. Not recommended.
  • The precompiled header file (if used)
    The precompiled header is required to be included before all others because all text before the precompiled header is included is ignored.
  • This file's header file
    Including the source file's header file before all others (except the precompiled header) is very useful. When you compile the source file, you will also test its header file to make sure it is "self-sufficient". Self-sufficiency is an important quality of header files. Self-sufficient header files do not depend on the order of inclusion, and they help catch and prevent circular dependencies.
  • All the rest of the header files
    The order of the rest of the headers is generally a matter of preference (assuming that they are all self-sufficient). However, sometimes the order might be dictated by coding standards. In the absence of standards, here is a suggestion:
    • Group by scope, and order scopes from the most local to the most global. Ordering from the most local to the most global has two purposes: it extends the test for self-sufficiency and it allows local headers to override global/system headers. Is all this important? Not really.
    • Within each scope, group by module and order modules alphabetically.
    • Within each module, order files alphabetically.

Here's an example of including header files in a source file:

/* controller.c */
 
#include "precompiledheader.h"
 
/* This file’s header file */
#include "controller.h"
 
/* Header files in this file’s module */
#include "gamemenu.h"
#include "menus.h"
#include "preferences.h"
 
/* Header files in sibling or parent modules */
#include "../UserInput/userinput.h"
#include "../UserInput/vibration.h"
 
/* Header files in unrelated modules */
#include "Zap/button.h"
#include "Zap/cycler.h"
#include "Zap/dialog.h"
#include "Zap/zap.h"
 
/* Standard library header files */
#include <stdio.h>
 
...