Why does `int x; extern int x;` not compile? [duplicate] - c

In the following program, I thought that extern int i; will change the following i to refer to the i defined outside main:
#include <stdio.h>
extern int i=1; // warning: 'i' initialized and declared 'extern'
int main()
{
int i=2;
printf("%d\n", i);
extern int i; // error: extern declaration of 'i' follows declaration with no linkage
printf("%d\n", i);
return 0;
}
What is the reason of the "error: extern declaration of 'i' follows declaration with no linkage", where "declaration with no linkage" refers to int i=2;?
After I remove int i=2 in main,
the error is gone,
the warning "warning: 'i' initialized and declared 'extern'" on extern int i=1; also disappear . Why is that?
Thank you for explanations!

#include <stdio.h>
int i=1; // external variable
int main()
{
int i=2; // local variable
printf("%d\n", i); // print local variable i==2
{
extern int i; // point to external variable
printf("%d\n", i); // print external variable i==1
}
return 0;
}

Once you define a variable named i inside your main function, the i at file scope is masked and cannot be accessed (unless you have its address).
When you later add the declaration extern int i, this conflicts with the local variable named i at the same scope since locals can't have external linkage. It does not give you access to the global i.
When you remove the local i, the extern int i declaration matches up with the definition at file scope, so there is no error. As for the warning on extern int i=1;, that did not go away for me on gcc 4.1.2, so that depends on the compiler.

Question: What is the reason of the "error: extern declaration of 'i' follows declaration with no linkage", where "declaration with no linkage" refers to int i=2;?
Answer: We do not need to use the extern keyword here on line 3 when it is a single file in a program and there is no other file in the same program or other location on the same file where the variable int i has its definition. There are two main reasons we can use extern keyword in C:
1. When we want to declare a variable explicitly/globally but without its definition.
2. To make the variable globally visible from any other file in a multi-file program or other location of the same file (see Ihdina's exmaple for this scenario).
Compiling your code on my system I get the following error,
error: extern declaration of 'i' follows non-extern declaration .
which totally makes sense that the compiler detects the extern on line 9 as a duplicate declaration of the same variable int i on line 7.
Question: After I remove int i=2 in main,
the error is gone,
the warning "warning: 'i' initialized and declared 'extern'" on extern int i=1; also disappear . Why is that?
Answer: After removing the int i=2; the error was gone on my system but still I have the following warning message:
warning: 'extern' variable has an initializer [-Wextern-initializer]
Basically my system (Apple LLVM version 8.1.0 (clang-802.0.42)) does not like the explicit initialization with extern keyword. So, you should modify your code as per Ihdina's answer which compiles without error.

Related

Understanding `extern` storage class specifier in C

Consider given C codes :
#include<stdio.h>
extern int i;
int main(){
printf("%d", i);
return 0;
}
It gives Compilation error. While if I initialize extern int i=10; then output is 10.
#include<stdio.h>
extern int i=10; //initialization statement
int main(){
printf("%d", i);
return 0;
}
And also, if I assign int i=10;then output is 10.
#include<stdio.h>
extern int i;
int i=10; //assignment
int main(){
printf("%d", i);
return 0;
}
And
#include<stdio.h>
extern int i;
int main(){
int i=10; //assignment
printf("%d", i);
return 0;
}
Variation :
#include<stdio.h>
extern int i;
int i=20;
int main(){
int i=10;
printf("%d", i);
return 0;
}
Since, int i is local variable, so output is 10.
Please, can you explain some important point about extern storage class in C
I read somewhere, a declaration declares the name and type of variable or function. A definition causes storage to be allocated for the variable or the body of the function to be defined. The same variable or function may have many declaration, but there can be only one defition for that variable or function.
Consider
int i;
declared outside all the functions of the programme including main.
This means i will have
file scope
static storage duration
space is allocated for i. #This is important.
Consider
extern int i;
declared outside all the functions of the programme including main.
This means i will have
file scope
static storage duration
i is only declared, not defined which means space is not allocated.
i is assumed to be defined somewhere else, may be, in an include file
Consider
extern int i=10;
declared outside all the functions of the programme including main.
This is the case where you're initializing the extern variable i. In this case
Space is allocated for i.
i will be initialized to 10.
The keyword extern is neglected which means i is NOT declared only.
Note
For extern int i it is mandatory that the variable should be defined somewhere else, ie in another source file. If this is not the case, you will a compile-time error.
The extern storage class specifier is used to give a reference of a global variable that is visible to ALL the program files. When you use 'extern', the variable cannot be initialized however, it points the variable name at a storage location that has been previously defined.
when the code references a symbol via the extern modifier, it means the symbol is actually defined elsewhere rather than in the current file.
An exception, if the extern modififier is used for a symbol that is actually defined in the current file, that is OK.
The extern int i; declaration just tells the compiler that there somewhere (in this or another source) exists an actual declaration of i in global scope. It's not in itself the actual declaration of i. Therefore it's inappropriate to assign a value to i in that declaration (which is why the second try is invalid). Your first attempt is invalid since you don't have an actual declaration of i.
Your third is OK though as you have an actual declaration of i, but you wouldn't have to have the extern int i; declaration.
Your last samples involves i in both local and global scope. In such a case the variable in local scope will be used. That's why you don't get 20 printed.

Declaration and Definition issue

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.

extern storage class variable inside main function [duplicate]

This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Closed 7 years ago.
I get very confused with the static and extern storage classes. I do not understand what is wrong with the below code snippet. I expect the printf to print the value Zero. The build is failing with the error "Undefined reference to 'i' ". I expect the statement "extern int i" to be a valid C statement. Is it not?
#include<stdio.h>
void main()
{
extern int i;
printf("%d", i);
}
In the function main
extern int i;
is a declaration of i, not definition. It must be defined somewhere.
#include<stdio.h>
int i; //definition
int main()
{
extern int i; //declaration
printf("%d", i);
}
In this example, the declaration is valid, but can be omitted.
When you declare a variable as extern inside a function, the compiler thinks that the variable is defined in some other translation unit. If it's not defined anywhere else, then you will get a linker error saying that the linker can't find the variable.
see when you are using extern storage class in the main then our compiler use to search the declaration of the variable in the perticular location ,here extern stands for compiler that this variable is declared at any location in the program it can be local or outside the scope , if it dont found any declaration then it gives this linking error becoz it is unable to found the variable declaration.

Strange behaviour of extern in c

I am surprised with the following behaviour of extern.
When I run this
#include<stdio.h>
int main()
{
extern int a;
printf("%d\n", a);
return 0;
}
int a=20;
OUTPUT: 20(in gcc Linux 32-bit,which seems OK)
But when I declare the variable a inside main():
#include<stdio.h>
int main()
{
extern int a;
int a=20;
printf("%d\n", a);
return 0;
}
OUTPUT:
extern.c: In function ‘main’:
extern.c:5:9: error: declaration of ‘a’ with no linkage follows extern declaration
extern.c:4:16: note: previous declaration of ‘a’ was here
Why I am getting the error now after changing the scope of a from global to local?Why it now doesn't allow redeclaration of a ,whereas it allowed in previous case.
The point of an extern declaration is to tell the compiler about a global variable or function used by multiple compilation units (.c files), but defined and allocated in a single compilation unit. The extern declaration is placed in a header file included by all units, and a single compilation unit contains the actual definition, therefore seeing both.
Your first example is legal C: you are declaring that a will refer to an externally defined variable, and then proceed to define that variable in the current compilation unit. Normally the extern declaration would be included from a header file and therefore appear to the compiler on top-level, not inside the function, but the compiler doesn't care either way. In other words, here there is no redefinition, only definition following declaration.
Your second example declares a to have external linkage, and then proceeds to define it as a local variable in main. The declaration and the definition are obviously incompatible - if a is a local variable, it cannot be defined and allocated in only one place - it will instead be automatically allocated on the stack every time the function is called. This incompatibility results in the error diagnostic.
In the first example, you are telling to the compiler: "hey, I have this variable called a that is defined somewhere else.", and then you use it. That's fine.
#include<stdio.h>
int main()
{
extern int a;
printf("%d\n", a);
return 0;
}
int a=20;
In the second example, you are also telling to the compiler that there is somewhere in the program a variable called a you want to use, and then you declare a new variable with the same name on your stack. That does not make much sense and the compiler says 2 things: can't find any declaration of variable a in the program and variable a already exists (if you fix the first error, it will).
#include<stdio.h>
int main()
{
extern int a;
int a=20;
printf("%d\n", a);
return 0;
}
When you declare a global variable, its memory is allocated when the program is launched (it's in the binary file and mapped in memory). When you declare a local variable, the memory is allocated on the stack, during the execution of the function. You can't refer with extern to a variable that does not exist yet.

working of extern keyword

I have defined a variable in one file and declared it in another file using the extern keyword. but i have declared it with different datatype..
file1.c
char i;
main()
{
foo();
}
file2.c
void foo()
{
extern int i;
i = 130;
printf("%d", i);
}
In the above program, memory is allocated for 'i' in the main function as char datatype.
And the answer after executing should be negative(-127). But it prints 130. Whatever the value assigned to 'i' in the foo() function is printed not only 130.
"I have defined a variable in one file and declared it in another file using the extern keyword". That is just not true. char i and in main is not in any way related to int i in foo.
The variable you define as char i inside main has no linkage. It cannot be referred to by name from anywhere else in the program besides that main function. There's simply no way to do it in C. It is a local variable.
Your extern int i; declaration inside foo has absolutely no relation to that local char i; variable from main. It declares a completely different, independent variable i. The extern int i declaration in foo refers to a variable i with external linkage, i.e to a global variable i. You are still required to define that i somewhere. That i will have to be defined at file scope (since this is the only way to define a variable with external linkage). If you don't define it your program will not compile.
Entities with external linkage and entities with no linkage live in completely separate worlds. They know nothing about each other and never interact or interfere with each other.
As I said above, the code you posted in your question simply won't compile. The linker will tell you that you forgot to define the int i variable with external linkage that which you declared in used in foo. Yet, your post suggests that the code compiled successfully. This would simply mean that the code you posted is either inaccurate or incomplete. If the code is accurate, then somewhere else in your code you also defined a global variable int i. This is the global variable your foo works with, while the char i in main has absolutely nothing to do with anything.
What you have now, after your edit, is an invalid program again, albeit for a different reason. You defined a global variable char i in file1.c and then you attempted to link to it in file2.c. However, in file2.c you lied to the compiler by telling it that the global variable i has type int, while in reality it has type char.
The behavior of such program is undefined. It is illegal to use inconsistent types when declaring an entity with external linkage. If you declared a global variable of type char in one translation unit, you are not allowed to declare the same global variable with any other type in other translation units.
Some compilers might catch your error and refuse to compile the program. Most C compilers will not catch this error though. Instead the will produce a program that causes undefined behavior. This is what you got in your case. In your case that undefined behavior happened to manifest itself by printing 130 after you assigned 130 to your variable. Why you suddenly find it strange I don't know. Why you expect it to print -127 I don't know either.
Analysis — What is wrong with the code
In your code:
file1.c
int main(void)
{
char i; // Warning: unused variable
foo();
}
file2.c
void foo(void)
{
extern int i;
i = 130;
printf("%d", i);
}
The variable i in main() is wholly unrelated to the i referred to in foo(). The variable i in main() is strictly local to main() and is not passed to foo(); foo() is unable to see that i.
On Mac OS X 10.7.5 with GCC 4.7.1, the files compile separately, but they can't be linked because there is no definition for variable i.
If we move the variable i outside of main(), then the program links:
file2.h
extern void foo(void);
file1.c
#include <stdio.h>
#include "file2.h"
char i = 'A';
int main(void)
{
printf("i = %d (%c)\n", i, i);
foo();
printf("i = %d (%c)\n", i, i);
return(0);
}
file2.c
#include "file2.h"
#include <stdio.h>
void foo(void)
{
extern int i;
i = 130;
printf("i = %d (%c)\n", i, i);
}
This now links and runs, but it invokes undefined behaviour. The linker does not notice that the size of i should be sizeof(int) but is sizeof(char). The assignment in foo(), though, goes trampling out of bounds of the i that is allocated. It doesn't cause visible damage in this program, but that's pure luck.
When I run it on a little-endian machine (Intel x86/64), the output is:
i = 65 (A)
i = 130 (?)
i = -126 (?)
When I ran it on a big-endian machine (SPARC), I got a different result (which isn't very surprising; the behaviour is undefined, so any result is valid):
i = 65 (A)
i = 130 (?)
i = 0 ()
The most significant byte of the 4-byte integer was written over the only byte of the 1-byte character, hence the zero in the third line out output. Note too that it was lucky that the character was allocated an address that was a multiple of 4 bytes; that was not guaranteed and a misaligned address for an int would have caused a bus error (though experimentation suggests that it doesn't happen on SPARC even when i is forced onto an odd address; I'm not sure what is happening).
Synthesis — Correct Handling of extern
The correct way to handle this is to avoid writing external variable declarations such as extern int i; in any source file; such declarations should only appear in a header that is used everywhere the variable needs to be used.
file2.h
extern char i;
extern void foo(void);
With that change in place (and the corresponding extern int i; removed), then the output is self-consistent:
i = 65 (A)
i = -126 (?)
i = -126 (?)
Note the role of the header in keeping both file1.c and file2.c in line with each other. It ensures that the definition in file1.c matches the declaration in file2.h, and the use of file2.h in file2.c ensures that the declaration used there is correct, too. See also What are extern variables in C.
The extern declaration inside foo has absolutely no relation to that local char variable.
As far as I know, extern can be put in front of a variable declaration.
Perhaps this is a bit more confusing.
Doing that tells the compiler you want to share the variable between different .c files.
However, there has to be one .c file where the variable is declared without the extern in front of it.
Note: You're example wouldn't work anyway, as extern has no effect on local variables.
extern is a way to tell the compiler some variable you are using is implemented in another object file that you promise that you will link at link time. It is often used in library header files that involve global variables to tell the compiler that the variable is actually implemented in the library file.
Ex:
file1.c:
int thing;
int bork(int val) {
return thing += val
}
file2.c
extern int thing
int main() {
thing + 2;
}
In the case when i is declared in one file as global variable then only it has external linkage.
Linker only looks for the symbol i which will be resolved at link time ,but types are not resolved by linker so I think it's Undefined Behavior when i is of different type and defind as global variable in one file and extern declaration is done in other file.
You are LYING to the compiler about the size of i. The compiler goes by what you have told it in foo, so you are getting the integer representation. Unfortunately, it won't really work reliably, because you have also written three bytes beyond your char i;
If you add char j = 11; and then print j in main after you call foo();, you'll notice that j is not 11 any more.
Lying to compilers is a bad idea. You get found out sooner or later!
In file1.c, i is defined (and declared implicitly) globally.
char i;
main()
{
foo();
}
file2.c extern is used with a variable i, it’s only declared not defined.
extern char i;
void foo()
{
printf("%d", i);
}

Resources