Q: What's the best way to declare and define global variables and functions?
A: First, though there can be many declarations (and in many translation units) of a single global variable or function, there must be exactly one definition. [footnote] For global variables, the definition is the declaration that actually allocates space, and provides an initialization value, if any. For functions, the definition is the ``declaration'' that provides the function body. For example, these are declarations:
extern int i; extern int f();and these are definitions:
int i = 0; int f() { return 1; }(Actually, the keyword extern is optional in function declarations; see question 1.11.)
When you need to share variables or functions across several source files, you will of course want to ensure that all definitions and declarations are consistent. The best arrangement is to place each definition in some relevant .c file. Then, put an external declaration in a header (``.h'') file, and #include it wherever the declaration is needed. The .c file containing the definition should also #include the same header file, so the compiler can check that the definition matches the declarations.
This rule promotes a high degree of portability: it is consistent with the requirements of the ANSI C Standard, and is also consistent with most pre-ANSI compilers and linkers. (Unix compilers and linkers typically use a ``common model'' which allows multiple definitions, as long as at most one is initialized; this behavior is mentioned as a ``common extension'' by the ANSI Standard, no pun intended. A few very old systems might once have required an explicit initializer to distinguish a definition from an external declaration.)
It is possible to use preprocessor tricks to arrange that a line like
DEFINE(int, i);need only be entered once in one header file, and turned into a definition or a declaration depending on the setting of some macro, but it's not clear if this is worth the trouble, especially since it's usually a better idea to keep global variables to a minimum.
It's not just a good idea to put global declarations in header files: if you want the compiler to be able to catch inconsistent declarations for you, you must place them in header files. In particular, never place a prototype for an external function in a .c file--if the definition of the function ever changes, it would be too easy to forget to change the prototype, and an incompatible prototype is worse than useless.
See also questions 1.24, 10.6, 17.2, and 18.8.
References:
K&R1 Sec. 4.5 pp. 76-7
K&R2 Sec. 4.4 pp. 80-1
ISO Sec. 6.1.2.2, Sec. 6.7, Sec. 6.7.2, Sec. G.5.11
Rationale Sec. 3.1.2.2
H&S Sec. 4.8 pp. 101-104, Sec. 9.2.3 p. 267
CT&P Sec. 4.2 pp. 54-56