From External Variables Wiki:
If neither the extern keyword nor an
initialization value are present, the
statement can be either a declaration
or a definition. It is up to the
compiler to analyse the modules of the
program and decide.
I was not able to fully grasp the meaning of this statement with respect to C. For example, does it imply that:
int i;
is not necessarily a declaration (as I have been assuming until now), but could be a definition as well (by definition of Definition & Declaration on the same webpage, no puns intended)?
In a nutshell, is the above statement:
a. just a declaration, or
b. declaration + definition?
Reference: Variable declaration and definition
Summary of answers received:
Declaration Definition Tentative Definition Initialized
int i; (inside a block) Yes Yes No No
int i=5; (inside a block) Yes Yes No Yes(to 5)
int i; (otherwise) Yes No Yes Yes(to 0)
extern int i; Yes No No No
All definitions are declarations but not vice-versa.
Assuming it's at file scope it's a 'tentative definition'. From 6.9.2/2 "External object definitions":
A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.
This means that it would be valid to also have the following in the translation unit:
int i = 42;
since that declaration has an explicit initializer, it's the definition of the variable i
.
As far as if the declaration is in a block scope, the standard says the following (6.2.2/2 "Linkages of identifiers"):
Each declaration of an identifier with
no linkage denotes a unique entity.
...
(paragraph 6) The following
identifiers have no linkage: ... a
block scope identifier for an object
declared without the storage-class
specifier extern.
So in block scope, the declaration would be a definition as well.
The C standard says that
A definition of an identifier is a declaration for that identifier that: for an object, causes storage to be reserved for that object (…)
Definitions encompass declarations, i.e., every definition is necessarily a declaration, so it doesn’t make sense to say that
int i;
is not a declaration. It is a declaration which also happens to be a definition. Or, it is a definition, hence a declaration.
In the context of variables:
A declaration of a variable is a statement which describes how this variable looks like. So:
extern int x;
in global scope translates to: "somewhere in the code, there's a variable called x
which has type int
and extern linkage. A declaration is necessary before you ever refer to x
. (The same goes to function declarations.)
A definition is a statement which creates an instance of this variable. So:
int x;
in global scope creates a single variable of type int
with extern linkage. So if you'd put that line in a header, every translation unit including that header would try to create its own copy of x
, which is undesirable - that's why we only have declarations in header files. The same goes to functions: if you provide the function body, it's a definition.
Also, formally, every definition is a kind of declaration, as it also has to specify how this variable/function looks like - so if a definition already exists in a given scope, you don't need any additional declarations to use it.
From the C99 spec:
A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.
So this is one case in which a simple declaration without an initializer can be a declaration.
As C uses the terms:
A "definition" creates something (which occupies some sort of memory). It also describes something. This means a "definition" is also a "declaration".
A "declaration" just describes something. The idea is that the compiler needs to know how to build the code that uses the thing defined elsewhere. Later, the linker then links the use to the something.
Declarations allow you to compile code and link it (later) as a separate step.