Sunday, February 12, 2012

Header files

How can we avoid multiple inclusion of a header file?

Guidelines for variable declarations in header files:
  • A header file only contains extern declarations of variables - never static or unqualified variable definitions.
  • For any given variable, only one header file declares it (SPOT - Single Point of Truth).
  • A source file never contains extern declarations of variables - source files always include the (sole) header that declares them.
  • For any given variable, exactly one source file defines the variable, preferably initializing it too. (Although there is no need to initialize explicitly to zero, it does no harm and can do some good, because there can be only one initialized definition of a particular global variable in a program).
  • The source file that defines the variable also includes the header to ensure that the definition and the declaration are consistent.
  • A function should never need to declare a variable using extern.
  • Avoid global variables whenever possible - use functions instead.

Violating the guidelines

Note 1: if the header defines the variable without the extern keyword:

faulty_header.h

int some_var;    /* Do not do this in a header!!! */
Then each file that includes the header creates a tentative definition of the variable.
Note 2: if the header defines and initializes the variable, then only one source file in a given program can use the header:

broken_header.h

int some_var = 13;    /* Only one source file in a program can use this */
Note 3: if the header defines a static variable (with or without initialization), then each source file ends up with its own private version of the 'global' variable.

seldom_correct.h

static int hidden_global = 3;   /* Each source file gets its own copy  */
When the variable is actually a complex array, this can lead to extreme duplication of code. It can, very occasionally, be a sensible way to achieve some effect, but that is rather unusual.

Note, in particular, that the header declaring the global_variable is included in every file that uses it - including the one that defines it. This ensures that everything is self-consistent.Similar concerns arise with declaring and defining functions - analogous rules apply.

Avoid multiple inclusion:

Any header should be protected against reinclusion, so that type definitions (enum, struct or union types, or typedefs generally) do not cause problems. The standard technique is to wrap the body of the header in a header guard:
#ifndef FILE3B_H_INCLUDED#define FILE3B_H_INCLUDED
...contents of header...
#endif /* FILE3B_H_INCLUDED */
The header might be included twice indirectly. For example, if file4b.h includes file3b.h for a type definition that isn't shown, and file1b.c needs to use both header file4b.h and file3b.h, then you have some more tricky issues to resolve. Clearly, you might revise the header list to include just file4b.h. However, you might not be aware of the internal dependencies - and the code should, ideally, continue to work.
Further, it starts to get tricky because you might include file4b.h before including file3b.h to generate the definitions, but the normal header guards on file3b.h would prevent the header being reincluded.
So, you need to include the body of file3b.h at most once for declarations, and at most once for definitions, but you might need both in a single translation unit (TU - a combination of a source file and the headers it uses.

Difference between  < > and " "
The #include <XX> searches the system include path.
The #include "XX" searches the user include path then the system include path.

Useful Links:
http://embeddedgurus.com/barr-code/2010/11/what-belongs-in-a-c-h-header-file/
http://stackoverflow.com/questions/1433204/what-are-extern-variables-in-c

No comments:

Post a Comment