Declaration and Definition issue - c

I know this question has been asked many times,but I don't find any relevant answer.
According to C
int x; //definition
extern int x; //declaration
int func(void); //declaration
int func(void) //definition
{
}
My first question is if int x is definition,then why compiler shows an redeclaration error
header files
int main()
{
int x,x; //for this it shows redeclaration error
}
And my second question is if I am defining the var x,twice it doesn't show any error
header files
int x;
int x;
int main()
{
}
I am using window 7 and DevCpp 5.6.2
Edited :
header files
int y;
int main()
{
int x;
}
x and y are definition here?

A declaration of a variable of at file scope without an initializer (and without storage class specifier) is a tentative definition:
int i;
It is valid to have multiple tentative definitions of the same variable in the same source file:
int i;
int i;
the behavior specified by C is as if there is a declaration at the top of the source file and at the end of the source file there is a int i = 0;.
At block scope there is no tentative definition and declaring the same variable multiple times in the same block is invalid.

Regarding the first question:
int x is both declaration and definition, whereas extern int x is only declaration.
This is why you get a redeclaration error.

Your first code, gets redeclaration error, because, in your case, x is having no linkage (local variable) and as per C11, chapter 6.7,
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,....
Your second code, compiles because the redeclaration is allowed, as both the statements reside in the global scope having external linkage.
Ref:
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

Related

Extern declaration follows non-extern declaration in same scope

#include <stdio.h>
extern int x;
int main()
{
int x;
x = 1;
printf("%d", x);
}
#include <stdio.h>
int main()
{
extern int x;
int x;
x = 1;
printf("%d", x);
}
I am learning about extern keyword and I was told that the word extern is used to declare variable and compiler will not allocate for this variable.
But when I write 2 codes, the first code run normally and the second has an error.
Please help me explain why it has this difference. Thanks.
Conflicting Declarations in Same Scope
When extern int x; appears outside a function, it declares x at file scope. Then, when int x; appears inside the function, it declares a new instance of x that is unrelated to the earlier extern int x;. This is allowed by the C language, so the compiler does not complain about it.
When extern int x; appears inside the function, it declares x at block scope. Then, when int x; appears after it, it attempts to declare a different x in the same scope. This is not allowed by the C standard, so the compiler reports an error.
The extern keyword is not particularly relevant here—the error is caused by the fact that there are two conflicting declarations of the same identifier. For example:
char c;
int main(void)
{
char d;
int c; // Allowed, new declaration in new scope.
int d; // Not allowed, conflicting declaration in same scope.
}
Rules About Declarations
The rules about C declarations have some irregularities due to the history of C development. Consider these declarations at file scope:
extern int x;
int x;
The first declaration does (or does not do) several things:
It says x is an identifier for an int.
It says x has external linkage, meaning it can be made (during linking of the object modules) to refer to an object named x declared somewhere else.
It does not define an int.
For the second declaration:
It says x is an identifier for an int.
It says x has external linkage (because external is the default for declarations for objects without a storage class specifier like static outside functions).
It defines an int. (It is actually a tentative definition, but we will not deal with that here.)
Both of these declarations say x is an identifier for an int and has external linkage. The difference between them is the first does not define an object (it merely says x is a name for an object defined somewhere else) and the second does define an int (so it is the somewhere else). So these declarations do not conflict and are allowed.
On other hand, consider these same declarations inside a function. Then they are at block scope.
Then extern int x; has the same meaning as above: x is an identifier with external linkage for an object defined elsewhere.
But int x; has a different meaning. Instead of saying x has external (or internal) linkage, it says x has no linkage, because no linkage is the default for declarations in block scope. This creates a conflict because C 2018 6.7 3 says an identifier with no linkage shall not be declared more than once in the same scope (and name space, not addressed here) except for typedef names and tags with certain conditions.
Scopes
C has four kinds of scopes:
File scope is for declarations outside of functions and lasts to the end of the source file being compiled.
Block scope is for declarations inside functions and lasts until the end of a block (discussed below).
Function prototype scope is for declarations in the parameters of function prototypes. (For example, in void foo(int n, float a[n][n]);, n and a have function prototype scope.)
Function scope is for labels to be used in goto statements.
A compound statement is a list of declarations and statements inside { and }. Each compound statement is a block, which creates a new scope for declarations. The main body of a function is a compound statement that is a block, and it may have additional compound statements inside it, each starting a new scope.
Blocks are also created by switch, if, do, while, and for statements, but they are largely unimportant for the first four of those, as only the for statement provides an opportunity for further declarations. For example, in a for statement, you can write for (int x = 3; x < 20; ++x), and that creates a new instance of x because the for statement starts a new block.

c - static and extern one again

I'm checking various situations that could happen in declarations with different linkages, and I have 2 questions.
I. I have the following code:
#include <stdio.h>
static int a = 19;
int main(void)
{
extern int a;
{
extern int a;
printf("braces - %d\n", a);
}
printf("main - %d\n", a);
}
which compiles well with both clang and gcc, with the same result of 19 being printed in both pritfs. As i may understand, all as are static as per 6.2.2., 4) of the Standard. The only thing that I don't understand in it is that why file-scope a is visible for a in main and braces? Should't the file-scope one be hidden as per footnote 31? When I define the other a in other file with different value, both printfs` output is still 19.
II. Now I do the following:
#include <stdio.h>
static int a = 19;
int main(void)
{
int a; //change in this line
{
extern int a;
printf("braces - %d\n", a);
}
printf("main - %d\n", a);
}
gcc yells variable previously declared ‘static’ redeclared ‘extern’, while clang acts normal and prints a = 0 for a in main (yes, it is garbage value) and still 19 in braces.
I guess gcc applies here 6.2.2. 7) of the Standard, while clang doesn't. Which one's interpretation is correct and what is going on in here?
I can only assume that gcc ''matches'' a in braces with a in main (which has no linkage) and makes it's linkage external, and then sees that it conflicts with file-scope static a. And, once again, why not making braces a refer to a in the other file (footnote 31?)?
My current understanding is, in fact, close to the one in the accepted answer in here, even though i do understand that C++ has differences from C (and i ask about C).
The only thing that I don't understand in it is that why file-scope a
is visible for a in main and braces?
The variable a declared in the file scope is visible in the block scope of main
static int a = 19;
int main(void)
{
extern int a;
//...
until the declaration in main redeclares the variable in the file scope. So the variable in main denotes the same variable declared in the file scope.
In the block scope of the compound statement
int main(void)
{
extern int a;
{
extern int a;
//...
the declaration of the variable a in the enclosing scope of main is visible until the declaration of the variable a in the block scope of the compound statement. So the variable declared in the compound statement denotes the same variable that is declared in the enclosing block scope of the function main. All three variables denote the same variable with the internal linkage.
As for the second program then according to the C Standard (6.2.2 Linkages of identifiers)
7 If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined
the program has undefined behavior because the variable declared in the block scope of the function main
static int a = 19;
int main(void)
{
int a;
// ...
hides the variable declared in the file scope with internal linkage. So according to the C Standard (6.2.2 Linkages of identifiers)
4 For an identifier declared with the storage-class specifier extern
in a scope in which a prior declaration of that identifier is
visible,31) 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.
the variable a declared in the block scope of the compound statement has external linkage. As a result the same identifier in the translation unit has external and internal linkages.

Usage of extern in the same file

I am confused with the usage of extern in the same file as shown in the code below. The first case was actually a solution to print a global variable in C (when same name local variable exist), but I am not able to understand how that worked and how the third case didn't work.
Case 1:
int a = 10;
int main()
{
int a = 20;
{
extern int a; // Is this telling the linker to use global variable?
printf("A value: %d\n", a);
}
return 0;
}
Case 2:
extern int a; // If in the above case extern was telling linker to use global variable
// then how in this local variable is getting referred
int main()
{
int a = 20;
{
printf("A value: %d\n", a);
}
return 0;
}
Case 3:
// int a = 10;
int main()
{
int a = 20;
{
extern int a; // Why now I get a linking error
printf("A value: %d\n", a);
}
return 0;
}
In the first case you have a global a that you override with a local (automatic) a that you again override with the global a (extern can only refer to variables global in some module). It will print 10.
In the second case you have a global a, that resides in this or in another module (c file/compilation unit) that you override with a local a. It will print 20.
In the third case you have a local a that you override with a global a that apparently does not exist in any of your compilation units, hence the linker error.
(Note that the edits to the code in the question seem to make parts of this answer no longer quite correct.)
Per 6.2.2 Linkages of identifiers, paragraph 4 of the C standard:
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.
So, in your first two cases, the inner extern int a; has a prior declaration - a global int a; in your first case or extern int a; in your second case - so the extern int a; declaration refers to the global.
For the third case, the remainder of paragraph 4 is relevant:
If no prior declaration is visible, or if the prior
declaration specifies no linkage, then the identifier has external linkage.
Also, paragraph 6 states:
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.
So the declaration in your third case is referring to an extern int a;
However, there is no actual int a; defined anywhere. And because the extern int a; in your third example appears in a block scope, and there is no actual definition of the int a; object elsewhere, your program fails to link.
Per 6.9.2 External object definitions, paragraph 2 states:
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 the block-scope extern int a; declaration of your third case does not qualify as a tentative definition.
Case 1:
The extern int a ; declaration declares a int a variable that is defined elsewhere and thus shadowing the a variable declared here : int a = 20 ;. The linker is then looking for a global variable a and finds it in the same file because of the int a = 10 ; declaration. The output is 10.
Case 2:
Here the extern int a ; declaration has no effect. Inside main the local variable declared here int a = 20 ; is used and hence the output is 20.
Case 3:
This is similar to case 1. It does compile correctly, but is does not link because extern int a ; declares a int a variable that is presumably defined elsewhere, which is not the case because you commented out the int a = 10 ; declaration.
Case 1:- In first code block extern int a; indicates that variable a is declared here but tells linker to find the definition of a above main() not in the main(). If linker is able to find the definition of a above main() then it will link otherwise results in linker error. In your case linker will take a as 10.
Case 2 :- In this case above globally declared extern int a; is telling to linker that definition of a may be in other file or in the same file in the main() function. Here extern int a; is saying that if you need it, there will be a definition of a with static duration and external linkage (a global variable) defined either in this file or in another file. That declaration is hidden by the definition inside main(), so the printf() uses the local variable.
This
printf("A value: %d\n",a);
consider locally declared a. So it prints 20.
Case 3 :- In this case the statement
extern int a; // Why now I get a linking error
causing linker error because linker will try to find definition of a above main() and it's not there(you commented) so it's results in linker error.

Why 'extern' storage class works differently in functions?

The following snippet works fine
extern int i;
int i;
int main(){
return 0;
}
Here what I got is, 'i' is declared and then defined. Since there is only one definition so thats perfectly fine.
int main(){
extern int i;
int i;
return 0;
}
Now, the above one gives the following error
new.cpp: In function ‘int main()’:
new.cpp:5:6: error: redeclaration of ‘int i’
int i;
^
new.cpp:4:13: note: previous declaration ‘int i’
extern int i;
Whats the problem here? Here also there is single definition of 'i'.
To understand the difference, you need to get familiar with a concept called tentative definition in C. To quote the C standard:
C11, draft, §6.9.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.
What you have in the first snippet is only a tentative definition for i. You can have as many tentative definitions for an object as you want (but only one definition is allowed):
int i; // tentative definition
int i; // tentative definition
int i; // tentative definition
int main(void) {
return 0;
}
is valid.
Here, i has external linkage and tentatively defined. If i is defined in somewhere in the same translation unit, then that'll be the actual definition of i. If there's no other definition of i is found in the translation unit, then this becomes the full definition as if it was defined like:
int i = 0;
int main(void) {
return 0;
}
But the second snippet int i; is not a tentative definition. Only objects with external linkage can be defined tentatively. In second snippet, The declaration extern int i; says i is defined elsewhere with external linkage. But the next line int i; says i is defined with no linkage (local automatic variables do not have any linkage -- this is not a tentative definition). So there's a conflict of definition for i. Hence, the first one snippet is fine but second isn't.
In the second case, there are two declarations of i in one scope. One says "there is a variable i defined outside this function"; the other says "there is a variable i defined inside this function". Without a new scope, that isn't allowed.
The rules are different inside and outside functions.
Note that you could use:
#include <stdio.h>
int i = 21;
int main(void)
{
extern int i;
i = 37;
{
int i = 57;
printf("%d\n", i);
}
printf("%d\n", i);
return 0;
}
This compiles OK (unless you include -Wshadow in your compilation options when using GCC or Clang), and produces 57 and 37 on the output (as pointed out by CoffeeAndCode in a comment).
See also How do I use extern to share variables between source files?

Why does redefining a static global variable give a compile-time error when redefining a global variable does not?

Compiling code 1 gives an error 'i redefined', but code 2 shows no similar error. Why is it so?
Code 1
static int i; //Declaring the variable i.
static int i=25; //Initializing the variable.
static int i; //Again declaring the variable i.
int main(){
return 0;
}
Code 2
int i; //Declaring the variable i.
int i=25; //Initializing the variable.
int i; //Again declaring the variable i.
int main(){
return 0;
}
Both should compile.
Both int i; and static int i; are tentative definitions in C as they do not have an initializer and are not extern. You are allowed multiple tentative declarations and at most one non-tentative definition for any object in a translation unit so long as the definitions don't conflict in type or linkage.
ISO/IEC 9899:1999 6.9.2:
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with a 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 definitions 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.

Resources