Rule #4. The header file contains only declarations, and is included by the .c file for the module. Put only structure type
declarations, function prototypes, and global variable extern declarations, in the .h file; put the function definitions and global variable
definitions and initializations in the .c file. The .c file for a module must include the .h file; the compiler can detect discrepancies
between the two, and thus help ensure consistency.
Rule #5. Set up program-wide global variables with an extern declaration in the header file, and a defining declaration in
the .c file. For global variables that will be known throughout the program, place an extern declaration in the .h file, as in:
!extern int g_number_of_entities;
The other modules #include only the .h file. The .c file for the module must include this same .h file, and near the beginning of
the file, a defining declaration should appear - this declaration both defines and initializes the global variables, as in:
!int g_number_of_entities = 0;
Of course, some other value besides zero could be used as the initial value, and static/global variables are initialized to zero by
default; but initializing explicitly to zero is customary because it marks this declaration as the defining declaration, meaning that this
is the unique point of definition. Note that different C compilers and linkers will allow other ways of setting up global variables, but
this is the accepted C++ method for defining global variables and it works for C as well to ensure that the global variables obey the
One Definition Rule.
Rule #6. Keep a module’s internal declarations out of the header file. Sometimes a module uses strictly internal components
that are not supposed to be accessed by other modules. If you need structure declarations, global variables, or functions that are used
only in the code in the .c file, put their definitions or declarations near the top of the .c file and do not mention them in the .h file.
Furthermore, declare globals and functions static in the .c file to give them internal linkage.
This way, other modules do not (and can not) know about these declarations, globals, or functions that are internal to the module.
The internal linkage resulting from the static declaration will enable the linker to help you enforce your design decision.
Rule #7. Every header file A.h should #include every other header file that A.h requires to compile correctly, but no
more. What is needed in A.h: If another structure type X is used as a member variable of a structure type A, then you must #include
X.h in A.h so that the compiler knows how large the X member is. Do not include header files that only the .c file code needs. E.g.
<math.h> is usually needed only by the function definitions – #include it in .c file, not in the .h file.
Rule #8. If an incomplete declaration of a structure type X will do, use it instead of #including its header X.h. If a struct
type X appears only as a pointer type in a structure declaration or its functions, and the code in the header file does not attempt to
access any member variables of X, then you should not #include X.h, but instead make an incomplete declaration of X (also called a
"forward" declaration) before the first use of X. Here is an example in which a structure type Thing refers to X by a pointer:
struct X;! /* incomplete ("forward") declaration */
struct Thing {
!int i;
!struct X* x_ptr;
!};
The compiler will be happy to accept code containing pointers to an incompletely known structure type, basically because
pointers always have the same size and characteristics regardless of what they are pointing to. Typically, only the code in the .c file
needs to access the members (or size) of X, so the .c file will #include "X.h". This is a powerful technique for encapsulating a
module and decoupling it from other modules.
Rule #9. The content of a header file should compile correctly by itself. A header file should explicitly #include or forward
declare everything it needs. Failure to observe this rule can result in very puzzling errors when other header files or #includes in
other files are changed. Check your headers by compiling (by itself) a test.c that contains nothing more than #include "A.h". It
should not produce any compilation errors. If it does, then something has been left out - something else needs to be included or
forward declared. Test all the headers in a project by starting at the bottom of the include hierarchy and work your way to the top.
This will help to find and eliminate any accidental dependencies between header files.
2