source file preprocessed (macros and #includes expanded) into a translation unit
compiler operates on one translation unit at a time; it uses no other information
i.e., once the #includes are brought in, the compiler does not go out of the unit to find any other info
this is not like Java where the compiler goes on a class file search when necessary.
the header files brought in by the #includes provide information about other separately compiled source files
the linker stitches together the object files produced by the (separate) compilations of the various source
files of the application
Linkage
Consistency of names, types, etc across translation units is vital
… and that's what the header (.h) files are all about
One major issue is declarations and definitions; one can often have multiple of the first, but in general only one definition.
Variables may or may not be visible across translation units:
Names that span multiple translation units are said to have external linkage
Names that are restricted to the translation unit in which they are defined are said to have internal linkage
static implies internal linkage, (and to some extent const)
local variables (and others … class scope variables?) — which are not visible to the linker whatsoever — are said to have no linkage
inline functions must be identically defined in all translation units
use header files to maintain this consistency
inline and external with the same name cannot co-exist
Header Files
Header files are used to provide the compiler about program entities contained within other translation units.
#include is replaced at the point of occurrence with the contents of the specified header
Standard libraries should be surrounded by <>'s
Files in the current directory should be surrounded by ""'s
For the purposes of the follwong discussion, assume we have a module (m.h and m.cpp) of C-style (non-member) functions, a class C
(in c.h/c.cpp), and an app (in app.cpp), and we're compiling app.cpp
What can go in a header file:
type definitions (structs, class)
templates
function declarations (headers)
inline functions
consts
other #includes
macro definition (#define)
conditional compilation (#ifndef
comments
All of the above either are entities that may be needed during the compilation of a source file wishing to use the facilities of the translation unit
corresponding to the header file.
What shouldn't go into a header file:
function definitions
variable 'declarations' (data definitions)
using directives
the header is a 'guest' in that file, and shouldn't be affecting the semantics of the including source file
Source files (i.e., .cpp) should never be included
included information is meant to supplement the compiler's information in order to process the
translation unit being compiler; NOT to be part of the behavior
The One-Definition Rule (ODR)
There can be at most one defintion of a class, template, etc in a program
Phrased slightly differenly:
Two definitions of a class, template, or inline function are accepted as examples of the same unique definition if and only if:
they appear in different translation units, and
they are token-for-token identical, and
the meanings of those tokens are the same in both translation units.
For practical purposes, this means that the above definitions should go into a header file which can then be included by each translation unit (i.e., file) and thus
is guaranteed to be identical across all such files.
Standard Library Headers
Use <>s for the include
Use ""'s for user-defined header files
No .h suffix
headers corresponding to C standard library headers use the C library name prefixed with a c, e.g. cstdlib
Using Header Files
Include Guards
Meant to prevent multiple inclusion of same header within a translation unit, which may lead to duplicate definition errors
// node.h
class Node {
…
};
// list.h
#include "node.h"
class List {
public:
…
void append(int val);
…
private:
Node *head;
};
// list.cpp
#include "node.h"
#include "list.h" // node.h is being brought into list.cpp a second time
…
void List::append(int val) {…}
…
Originally, this was avoided by only having .cpp files do a #include of header files. This was
problematic in that it meant analyzing the dependencies of the .h files to determine their order of appearance.
Having .h files be responsible for their own #include solved this problem, but introduced the multiple
inclusion issue
Two basic ways of solving this problem:
include guard
uses unique macro names to determine if .h file has already been seen during this compilation
first checks that macro has not been defined yet; if not defines macro, otherwise contents till #endif
are skipped
// node.h
#ifndef NODE_H // has NODE_H been defined? (NODE_H will only appear here -- at top of node.h)
#define NODE_H // if not, i.e., this is first encounter with node.h, define NODE_H
…
…
#endif // everything till #endif is skipp if NODE_H was already defined
Use a pragma: #pragma once
Programs
Collection of compilation / translation units combined by a linker
Unique definitions
Exactly one (global / non-member) function main
Program Termination
A program terminates by:
returning from main
calling exit
calling abort
throwing an uncaught exception
Advice
[1] Use header files to represent interfaces and to emphasize logical structure; §15.1, §15.3.2.
breaking up program into modules/classes encourages and improves logical structure
headers are then needed to transmit info across translation units; i.e., to provide interface information
[2] #include a header in the source file that implements its functions; §15.3.1.
this helps ensure the consistency of the implementation (header inthe function definition) and what is exported through the interface
[3] Don't define global entities with the same name and similar-but-different meanings in different translation units; §15.2.
[4] Avoid non-inline function definitions in headers; §15.2.2.
You'll end up with duplicate definitions most of the time
[5] Use #include only at global scope and in namespaces; §15.2.2.
[6] #include only complete declarations; §15.2.2.
[7] Use include guards; §15.3.3.
to prevent multiple inclusion of header files
[8] #include C headers in namespaces to avoid global names; §14.4.9, §15.2.4.
[9] Make headers self-contained; §15.2.3.
Any other headers required by a header should be included within that header
[10] Distinguish between users' interfaces and implementers' interfaces; §15.3.2.
[11] Distinguish between average users' interfaces and expert users' interfaces; §15.3.2.
[12] Avoid nonlocal objects that require run-time initialization in code intended for use as part of non-C++ programs; §15.4.1.