Barr Group TwitterBarr Group Vimeo


4.2.a. There shall always be precisely one header file for each source file and they shall always have the same root name.

4.2.b. Each header file shall contain a preprocessor guard against multiple inclusion, as shown in the example below.6

4.2.c. The header file shall identify only the procedures, constants, and data types (via prototypes or macros, #define, and typedefs, respectively) about which it is strictly necessary for other modules to be informed.

           i. It is a preferred practice that no variable ever be declared (via extern) in a header file.

          ii. No storage for any variable shall be allocated in a header file.

4.2.d. No public header file shall contain a #include of any private header file.


#ifndef ADC_H
#define ADC_H
#endif /* ADC_H */

Reasoning: The C language standard gives all variables and functions global scope by default. The downside of this is unnecessary (and dangerous) coupling between modules. To reduce inter-module coupling, keep as many procedures, constants, data types, and variables as possible privately hidden within a module’s source file.

   See also What Belongs in a C .h Header File?:

Enforcement: These rules shall be enforced during code reviews.


[6] The preprocessor directive “#pragma once” has the same purpose but is non-portable.


Owners of the 2008 or 2013 edition of the printed book should note that the words "defined" and "declared" were inadvertently swapped in the original phrasing of rules 4.2.c.i and 4.2.c.ii. The phrasing on this web page and in later print and PDF versions has been corrected to use those terms in a manner consistent with their formal meanings in the ISO C standards.

Identifiers beginning with an underscore and an uppercase letter are always reserved for any use.

Rule 4.2.a One header one C restriction excludes creating link-time substitutable files. This is an essential technique for automated testing and a good idea for handling variation in designs. For example having two different driver implementations with the same interface and the correct implementation is chosen at link-time to match the hardware. There would also be a third driver implementation to use as a test stub (fake, sky, mock) during unit testing higher level portable code.

Substitutable files IMO is better than preprocessor conditional logic for dealing with different hardware variants.

Another case where this rule could/should be broken it exemplified by stdio.h. It does not have a single c file. If you are making a facade over a subsystem, it is acceptable to have multiple implementation files.

You make a good point.  For now, note that you're doing this via the exception process.  In the future we will consider rewording the rule to allow for this specifically.

4.2.c - Let me add a preference to keeping struct details out of header files.

Prefer struct forward declaration in header files and full declaration of struct members in the C file, when possible.

For example:



typedef struct CircularBufferStruct CircularBuffer;

CircularBuffer * CircularBuffer_Create(unsigned int capacity);
void CircularBuffer_Destroy(CircularBuffer *);
bool CircularBuffer_IsEmpty(CircularBuffer *);
bool CircularBuffer_IsFull(CircularBuffer *);
bool CircularBuffer_Put(CircularBuffer *, int);
int CircularBuffer_Get(CircularBuffer *);
unsigned int CircularBuffer_Capacity(CircularBuffer *);
void CircularBuffer_Print(CircularBuffer *);


CircularBuffer is an abstract data type. No user of the data structure can know the internals as they are not published in the header file. And thus no user can become dependent on the inner details of how the CircularBuffer is managed.

That's generally good advice.  

There's a blog post on that and related points here: