This question already has answers here:
About Tentative definition
(2 answers)
In C,why is multiple declarations working fine for a global variable but not for a local variable?
(3 answers)
Closed 5 years ago.
/*How does this code compiles and executes in C?*/
#include <stdio.h>
int x= 9; //Varaible initialization
int x; //Variable declaration, same name
int main(void) {
printf("%d", x); //output: 9
return 0;
}
There should be an error while compilation as same variable is used. How come the code compiles?
From standard 6.9.2p2 you can know about this - this is known as tentative definition.
From here
A tentative definition is an external declaration without an initializer, and either without a storage-class specifier or with the specifier static.
A tentative definition is a declaration that may or may not act as a definition. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.
int i1 = 1; // definition, external linkage
int i1; // tentative definition, acts as declaration because i1 is defined.
So from these two references it is clear that the second one merely boils down a declaration or valid tentattive definition on standard words and the value it takes is the one assigned that is 1.
Sane goes here for you with the value of x being 9.
You can declare a global variable or function as many times as you wish. But you must have only one definition. The first line assigns the variable a value, so it is a declaration and definition combined. The second line does not assign a value, so it is only a declaration.
In Global scope two variable with same name is possible but one should be un-intialized(weak symbol) and another one should be initialized(strong symbol).
int x= 9; /* strong symbol i.e declaration with definition*/
int x; /* weak symbol i.e only declaration */
while choosing among two, priority is given two strong symbol.
Note : compiler won't allow to have two strong symbol at a time, that would be a re-definition of variable.
The second one is not a definition. It's a declaration.
From the ISO C standard draft N1570, Section 6.9.2:
1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.
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.
So when you write
int x;
in file scope, it's not necessarily a definition. It's a declaration, which is fine to be repeated.
This is called tentative definition in C. See more here, here and here.
Related
This question already has answers here:
About Tentative definition
(2 answers)
Closed 1 year ago.
This code gives me no re-declaration error.
#include<stdio.h>
int i;
int i = 27;
int main()
{
printf("%d",i);
return 0;
}
According to me I declared and defined an uninitialised global variable with 0 as default value.
And later re-declared, redefined and assigned it 27 value.
I was expecting it to give a re-declaration error because both i's are in same scope(global).
But I'm not getting any error why?
But below code gives me a re-declaration error as expected because of defining them in same scope.
#include<stdio.h>
int main()
{
int i;
int i = 27;
printf("%d",i);
return 0;
}
At file scope, this:
int i;
Is a tentative definition since there is no initializer. It will be considered an external definition if no other definition appears.
When you then do this:
int i = 27;
This constitutes an external definition for i which matches the prior tentative definition.
These terms are defined in section 6.9.2 p1 and p2 of the C standard:
1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external
definition for the identifier.
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 initialize requal to 0.
Your second code snippet defines a variable in block scope (not file scope), then defines it again in the same scope. That constitutes a variable redefinition.
In C this declaration in the file scope without an initializer
int i;
is a declaration of a variable and not its definition, So the next declaration
int i = 27;
is the definition of the variable.
You may declare a variable without its definition in a file scope several times though the declarations can be redundant.
C11 specifies in section 6.7 which declarations are also definitions:
A definition of an identifier is a declaration for that identifier that:
— for an object, causes storage to be reserved for that object;
[...]
I didn't find a comprehensive list of which object declarations cause storage to be reserved. Intuitively it is clear to me, but I wasn't able to get this information out of the C11 standard.
There's no definitive list because the standard just describes what are definitions and it's not in a single place. I'll try to sum it up here. I'll only use the type int here without any qualifiers (like const) for consistency.
If you add an initializer to a declaration, it's always a definition:
int x = 1;
Without an initializer, the following are definitions when they're in function scope:
int x;
auto int x; // auto is the default anyways
register int x; // register is just a hint, but would be "storage" as well
static int x; // also reserves storage, but with static duration
In file scope, the rules are a bit more complicated; the following are tentative definitions:
int x;
static int x;
The wording of the standard (§6.9.2p2) is:
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 means that they eventually "become definitions" if they are not found to refer to another definition.
With the storage class extern and without an initializer, you don't have a definition:
extern int x; // <- not a definition
AFAIK, this should be the complete set of rules. Please feel free to edit/comment if I forgot something.
When we declare a global variable, it is initialised to its default value. But when we initialise a variable using the extern keyword, why does the variable retain the value with which it is initialised using the extern keyword?
For instance, in the code below why is the output 9 and not a compile time error? Since there is no external linkage of variable x from any other source file, so x has two copies and we are initialising the variable twice so this should be an error. Please clarify this; I am a bit confused in the flow of this code.
#include <stdio.h>
extern int x=9;
int x;
int main()
{
printf("%d",x);
return 0;
}
extern int x = 9; means the same as int x = 9;. The extern keyword has no effect for a definition that already has external linkage and an initializer.
int x; is called a tentative definition.
This is described well by C11 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.
This translation unit does contain an external definition for x, so the tentative definition has no effect. It doesn't matter whether the external definition is before or after the tentative definition.
"external definition" means a non-tentative definition at file scope -- not to be confused with extern or "external linkage", although in your example x does happen to have external linkage.
So your code is exactly the same as:
int x = 9;
This question already has answers here:
Is it possible that a variable declared after the main has file scope?
(3 answers)
Closed 8 years ago.
Referring to the code below:
#include <stdio.h>
int a;
int a;
int main()
{
int b;
int b;
return 0;
}
Why does the compiler (GCC) complain of redeclaration for only variable 'b' and not 'a'?
redef.c: In function 'main':
redef.c:19: error: redeclaration of 'b' with no linkage
redef.c:18: error: previous declaration of 'b' was here
It's because a has external linkage and the standard states (C11, 6.2.2/2):
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.
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.
So, because a has external linkage, both those declarations refer to the same underlying variable. Because b has no linkage, the declaration refer to unique variables and therefore conflict with each other.
Quoting the C99 standard §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.
Therefore, both the statements
int a;
int a;
constitute tentative definitions. According to the above quoted part, the behaviour is as if
the two statements were replaced by
int a = 0;
However, b defined inside main is an automatic variable, i.e., it has automatic storage allocation. There cannot be two definitions of an automatic variable.
int a; int a; is a tentative definition. From 6.9.2p2:
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.
Tentative definitions are only permitted at file scope.
The reason that int b; int b; is illegal is because of 6.7p3:
If an identifier has no linkage, there shall be no more than one declaration of the identifier
(in a declarator or type specifier) with the same scope and in the same name space
Identifiers declared within a function and not static or extern have no linkage, this is describd in 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.
This question already has answers here:
Use of 'extern' keyword while defining the variable
(2 answers)
Closed 8 years ago.
I was trying out programs based on extern and as I understand, this is helpful when accessing variables across multiple files having only one definition.
But I tried a simple program as below without extern and thing seem to work when I expected it would fail during linking process
file5.c:
#include <stdio.h>
#include "var.h"
int a = 20;
int main() {
printf("\n File5.c a = %d", a);
test();
return 0;
}
file6.c:
#include <stdio.h>
#include "var.h"
int test() {
printf("\n File6.c a = %d",a);
}
var.h
int a;
As I have included var.h in all header files without extern, int a would be included in both the .c file and during linking, compiler should have thrown a warning or error message but it compiles file without any issue.
Shouldn't var.h have the following extern int a?
It is generally best if the header uses extern int a;. See also How do I share a variable between source files in C?
The standard says:
ISO/IEC 9899:2011 §6.9.2 External object definitions
Semantics
¶1 If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
¶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.
Thus, what's in the header is a tentative definition of the variable. At the end of the translation unit (TU) for file5.c, you have no longer got a tentative definition; the 'external definition' specified by int a = 20; has specified that. At the end of the TU for file6.c, you have a definition equivalent to int a = 0;.
When you try to link file5.c and file6.c, you should run into multiple definitions of a. However, there is a common extension, documented in the standard in Annex J:
J.5.11 Multiple external definitions
¶1 There may be more than one external definition for the identifier of an object, with or
without the explicit use of the keyword extern; if the definitions disagree, or more than
one is initialized, the behavior is undefined (6.9.2).
Your compiler is providing the extension identified by §J.5.11, and therefore (legitimately) not complaining.
580