The C11 standard specifies in section 6.7/5 which declarations are also definitions:
C11 6.7/5
A definition of an identifier is a declaration for that identifier
that:
— for an object, causes storage to be reserved for that object;
(...)
So is a declaration of a variable inside a block also a definition? For example:
void Bla(void) {
int a; // Is this declaration also a definition?
}
I have found the following two answers on stackoverflow, which state that declarations of variables inside blocks are also definitions:
https://stackoverflow.com/a/4769638
https://stackoverflow.com/a/45695028/9771101
However, the answer provided by "Michael Burr" refers to 6.2.2/2 "Linkages of identifiers" in order to explain that variable declarations in block scope are also definitions. For me, his reference does not answer my question. The answer in the second link does not provide any reference to the C standard. Is there any other paragraph in the C standard which can be used as a reference to confirm those answers?
Please provide a reference to the C standard.
Yes, a declaration of an "object" (the C standard avoids using the word "variable") at block scope is a definition, except when the declaration of that object uses the storage-class specifier extern, in which case it is not a definition.
Here is how to see that from the standard (all references are to N1570, which is the closest approximation to the official text of C2011 that is publicly available at no charge):
first, 6.2.2p6 says
the following identifiers have no linkage: ... a block scope identifier for an object declared without the storage-class specifier extern.
second, 6.7p5 says
A definition of an identifier is a declaration for that identifier that:
* for an object, causes storage to be reserved for that object;
and finally, 6.2.4 which you will need to read in its entirety, but the most important bits are in paragraph 5 and 6:
An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration ... its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
So, if you declare an object at block scope without extern, it has no linkage. An object with no linkage has automatic storage duration, unless it was declared with static, in which case it has static storage duration instead, see the parts of 6.2.4 I didn't quote. An object with automatic storage duration has storage reserved for it upon entry to the block it was declared within, and an object with static storage duration has storage reserved for it at program start (again, see the parts of 6.2.4 I didn't quote). Therefore, any declaration of an object that gives it no linkage is a definition.
(A declaration of an object at block scope with extern gives it external linkage and is not a definition. If you don't see why that is after reading through all of the sections I quoted and also 6.9, please ask a new question specifically about that.)
Section 6.2.2p6 of the C standard states:
In the set of translation units and libraries that
constitutes an entire program, each declaration of a particular
identifier with external linkage denotes the same object or
function. Within one translation unit, each declaration of an
identifier with internal linkage denotes the same object or
function. Each declaration of an identifier with no linkage
denotes a unique entity.
The part that's missing is section 6.2.2p6:
The following identifiers have no linkage: an identifier declared to
be anything other than an object or a function; an identifier
declared to be a function parameter; a block scope identifier
for an object declared without the storage-class specifier extern.
A variable declared inside of a block that does not have a storage class specifier (i.e. static or extern) has no linkage, and each declaration of a variable with no linkage is a unique object. Because the declaration is unique, it also qualifies as a definition.
See also section 6.7p7:
If an identifier for an object is declared with no linkage,
the type for the object shall be complete by the end of its
declarator, or by the end of its init-declarator if it has
an initializer; in the case of function parameters (including in
prototypes), it is the adjusted type (see 6.7.6.3) that is required to
be complete.
Related
I'm a bit confused by the wording in 6.9 p5 of N2310 C18:
If an identifier declared with external linkage is used in an
expression (other than as part of the operand of a sizeof or _Alignof
operator whose result is an integer constant), somewhere in the entire
program there shall be exactly one external definition for the
identifier; otherwise, there shall be no more than one. 164)
QUESTION: Is it obvious from this quote that the external definition somewhere in the program (if any) should also declare an identifier with external linkage?
As I emphasized somewhere in the entire program there shall be exactly one external definition for the identifier. It does not specify which linkage the definition should declare the identifier with. Example:
tu1.c:
int a = 10;
tu2.c:
static int a = 20;
Formally speaking we have one external definition for identifier a declared in tu1.c and another one in tu2.c so we could apply the quote I cited above to this example.
Although to denote the same entity identifiers declared in different should all be declared with external linkage as specified in 6.2.2/2:
In the set of translation units and libraries that constitutes an
entire program, each declaration of a particular identifier with
external linkage denotes the same object or function.
Which is not the case here.
See C11 §6.2.2 Linkages of identifiers:
… There are three kinds of linkage: external, internal, and none.
In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.
If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
Emphasis added.
If a file scope variable is specified with static, it has internal linkage and isn't relevant to a discussion of variables with external linkage.
Does a function have any storage class in C Language?
The answer is no. According to http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf (draft of C99) and http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf (draft of C11):
6.2.4 Storage durations of objects
1 An object has a storage duration that determines its lifetime.
Functions aren't objects, so they have no storage.
6.2.2 Linkages of identifiers
3 If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
This says that static applied to a function affects its linkage (there is no storage it could apply to).
The C standard doesn't formally define the meaning of storage class.
It does define what a "storage-class specifier" is --- it is one of the keywords typedef, extern, static, _Thread_local, auto and register.
Functions can be declared with storage-class specifiers extern or static.
The standard does mention objects having "storage class" in several places, for example
If the array object has register storage class, the behavior is undefined
but it is never defined what a storage class of an object is. One could reasonably assume that this is the storage-class specifier keyword that appears in one of the declarations, but it remains unclear what happens if some declarations of the same object have a storage-class specifier and others don't. It is also never defined what is the storage class of an object that doesn't have any declaration with a storage-class specifier.
It seems that one should avoid talking about storage classes of objects or functions altogether, and instead use related notions of storage duration and linkage which are precisely defined by the standard. When necessary, use phrases like "storage-class specifier X appears in a declaration", but not "object/function has storage class X".
I believe the answer is no linkage because the standard only guarantees that a file scope identifier with static storage duration have internal linkage. However, it seems that recursive calls to a function which has an identifier with static storage duration does not impose additional memory for local variables. In other words, at any stage of the recursive process, the identifier always denotes the same object, which is weird given that it has no linkage. Why is that?
void recursive(void) {
static int a;
printf("%d", &a); // it repeatedly spits out the same address.
recursive();
}
Local static variables have no linkage (or more precisely their linkage is none). From N1570 (C11 draft) 6.2.2 Linkages of identifiers (emphasis mine):
6) The following identifiers have no linkage: an identifier declared to
be anything other than an object or a function; an identifier declared
to be a function parameter; a block scope identifier for an object
declared without the storage-class specifier extern.
However static specifier imposes that such variable has static storage duration, which is kind of different thing. What you are refering to is lifetime of object. Such variables denotes objects, that have lifetime of whole execution of program and are intialized once, conceptually before program's actual startup.
6.2.4 Storage durations of objects:
2) The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists,
has a constant address,33) and retains its last-stored value
throughout its lifetime.34) If an object is referred to outside of its
lifetime, the behavior is undefined. The value of a pointer becomes
indeterminate when the object it points to (or just past) reaches the
end of its lifetime.
3) An object whose identifier is declared without the storage-class
specifier _Thread_local, and either with external or internal linkage or with the storage-class specifier static, has static storage duration. Its
lifetime is the entire execution of the program and its stored value
is initialized only once, prior to program startup.
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.
Why can't I have int a; in 2 C files. I intend to combine both to make executable.
I know from experience that I can't, but I want to find where the standard C99 says this and seal my understanding.
I am reading ISO C99 standard from http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf. It says on page 42:
6.2.2 Linkages of identifiers
1 An identifier declared in different
scopes or in the same scope more than
once can be made to refer to the same
object or function by a process called
linkage.There are three kinds of
linkage: external, internal, and none.
2 In the set of translation units and
libraries that constitutes an entire
program, each declaration of a
particular identifier with external
linkage denotes the same object or
function. Within one translation unit,
each declaration of an identifier with
internal linkage denotes the same
object or function. Each declaration
of an identifier with no linkage
denotes a unique entity.
3 If the declaration of a file scope
identifier for an object or a function
contains the storage-class specifier
static,the identifier has internal
linkage.
4 For an identifier declared with the
storage-class specifier extern in a
scope in which a prior declaration of
that identifier is visible,if the prior
declaration specifies internal or
external linkage, the linkage of the
identifier at the later declaration is
the same as the linkage specified at
the prior declaration. If no prior
declaration is visible, or if the
prior declaration specifies no linkage,
then the identifier has external
linkage.
5 If the declaration of an identifier
for a function has no storage-class
specifier,its linkage is determined
exactly as if it were declared with
the storage-class specifier extern.If
the declaration of an identifier for an
object has file scope and no
storage-class specifier, its linkage is
external.
After reading this it looks that if I declare a variable like say int a; in 2 source files. then both have external linkage as per rule 5 and 4. and then as per rule 2, both should refer to the same object. Then why does the compiler create problem. Where in the standard it is hinted that we can't declare like this in 2 source files and this should throw compilation error. Firstly, where in the standard, it says that int a is a definition, and then where it says that 2 instances of definitions are not acceptable. I know that it is not allowed from my experience, but it would be very useful to me, if I can find this in the standard and seal my understanding.
Do the following excerpts from the standard in combination amount to this rule? or I have missed that glue? :
A declaration specifies the
interpretation and attributes of a set
of identifiers. A definition of an
identifier is a declaration for that
identifier that: —for an object, causes
storage to be reserved for that
object; —for a function, includes the
function body; —for an enumeration
constant or typedef name, is the
(only) declaration of the identifier.
As discussed in 5.1.1.1, the unit of
program text after preprocessing is a
translation unit, which consists of a
sequence of external declarations.
These are described as ‘‘external’’
because theyappear outside anyfunction
(and hence have file scope). As
discussed in 6.7, a declaration that
also causes storage to be reserved for
an object or a function named by the
identifier is a definition.
An external definition is an external declaration that is also a definition
of a function (other than an inline
definition) or an object. If an
identifier declared with external
linkage is used in an expression
(other than as part of the operand of
a sizeof operator whose result is an
integer constant), somewhere in the
entire program there shall be exactly
one external definition for the
identifier; otherwise, there shall be
no more than one.
Thanks.
I think you need 6.9.2/2:
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.
and 6.9/5:
An external definition is an external declaration that is also a definition of a function
(other than an inline definition) or an object. If an identifier declared with external
linkage is used in an expression (other than as part of the operand of a sizeof operator
whose result is an integer constant), somewhere in the entire program there shall be
exactly one external definition for the identifier; otherwise, there shall be no more than one.
Basically, int a; is a tentative definition. You can have multiple tentative definitions in a single translation unit but the effect is the same as having one non-tentative external definition (e.g. something like int a = 0;). Having more that one definition of an object with external linkage in a program is a violation of 6.9/5.
Note that it is a "common extension" to allow more than one external definitions of an object so long as at most only one is initialized and the definitions agree (see J.5.11).