title
The terminologies "definition" and "declaration" in this article are adopted from The C++ Programming Language (Special edition) (_TC++PL_ for short). In C: A Reference Manual (_Reference_ for short) they are called "defining declaration" and "referencing declaration" respectively.
Why Care
Distinguishing definitions from declarations are important since header files containing definitions could cause subtle problems. For example:
If a header file which contains a definition is included by more than one source files, each translation unit will get its own copy of that definition after preprocessing. The best result you may expect is that you'll get "multiple definition" error on linkage (except for ODR in C++). But there are also chances that compiler silently give you multiple instances of the variable. So it's always better to not put any definition in header files except for "const" variables and ODR (refer to Section 9.2.1 of TC++PL for more about what a header files should/shouldn't contain) .
This article is based on Reference and TC++PL. It reflects the test results of gcc and g++ of version (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-20). However, according to Reference, other C compiler's behavior may differ.
Confusing Statements
The most confusing statements (which are also where differences between C and C++ exist) are following two kinds of statements:
int i; extern int i = 0;
For the first one, it is a definition in C++. In C the situation is rather
complicated. The statement is deemed as a declaration if there is a definition
in the same translation unit. Otherwise compiler will automatically define an
i
for you. But On linkage, variables defined by that means will be dealt
with specially. Reference says that different compilers may choose
different rules. According to test, GCC chooses which is called "Mixed Common
Model" (4.8.4) by Reference. That is: if there are more than one translation
unit contains such definition for i
, those definitions will be combined into
only one definition. Note how that is different from other kinds of
definitions: multiple-definition is just illegal.
As for the second one, it is illegal in C. But in C++, the extern
is
silently ignored.
For a full discussion on C/C++ compatibility for declaration (of a more general sense), please refer to section 4.9 of Reference.
Clearer Ones
In fact, there are more clear statements. They mean the same in C/C++ as well.
- All initializations (i.e. statements like following one) are definitions.
int i = 0; // definition
- All
extern
statements (except for the one discussed above) are declarations.extern int i; // declarations
- For functions and structures, following are declarations:
struct s; void f();
Section 9.2.3 of TC++PL detailed One Definition Rule (ODR). The ODR says that definitions of "class", "inline function", "template" can be repeated if and only if in different translation unit. Reference doesn't mention any rule alike. Nor did I find a way to test.
Advice
Avoid following statements, especially the first one:
int i; extern int i = 0;
Instead, using following kinds of statements for declarations and definitions respectively whenever possible:
int i = 0; // initialization for definition extern int i; // "extern" for declaration
Why?
- Those two kinds of statement are more portable not only between C and C++ but also among C compilers.
- Using initialization for definition helps to develop a good habit of initialize a variable when defining it: although compiler will initialize global variables for you, that is not the case for automatic variables.
Bibliography
- C: A Reference Manual
- http://www.china-pub.com/computers/common/info.asp?id=12626
- The C++ Programming Language (Special Edition)
- http://www.china-pub.com/computers/common/info.asp?id=3311
blog comments powered by Disqus