Barr Group TwitterBarr Group Vimeo

Rules

The following C coding rules relate to header files:

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

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

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

  1. It is recommended that no variable be declared (via extern) in a header file.
  2. No storage for any variable shall be defined in a header file.

Example

#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 hidden within a module’s source file.

Exceptions

It is acceptable to deviate from the common root name rule for the core application module (e.g., if “foomain.c” contains main(), its header file may be “foo.h”).

Under certain circumstances it may be necessary to share a global variable across modules. Whenever this is done, such a variable shall be named with the module’s prefix, declared volatile, and always protected from race conditions at each location of access.

Enforcement

These header file rules shall be enforced during code reviews.

Comments:

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:

#ifndef CIRCULAR_BUFFER_INCLUDED
#define CIRCULAR_BUFFER_INCLUDED

#include 

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 *);

#endif

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: 

What’s happening and how it’s done. Get in the know.

Sign Up for Our Newsletter

Receive free how-to articles, industry news, and the latest info on Barr Group webinars and training courses via email. 

To prevent automated spam submissions leave this field empty.