While I was reading the answers of Use of 'extern' keyword while defining the variable
One of the user answered these way
extern int a; // not a definition
extern int a = 42; // definition
I was expecting both are not definitions but declarations. I was thinking Both statements says that the variable is defined outside the function and we have to use extern keyword to use it. is this a mistake by him or is it really a definition ?
I know that
extern int a; // variable is already defined but its outside the function
extern int a=42 ; //I guess a variable is assigned a value but not a definition
but these statement
extern int a = 42; // user said its a definition and now i got confused
Please clear me with these.
Whenever initialisation is attempted, the statement becomes a definition, no matter that extern is used. The extern keyword is redundant in such a case because, by default, symbols not marked static already have external linkage.
It doesn't make sense to declare an external variable and set its initial value in the current compilation unit, that's a contradiction.
extern int a; is a declaration. It does not allocate space for storing a.
extern int a = 42; is a definition. It allocates space to store the int value a and assigns it the value 42.
here the variables are declared inside the main() function where its definition was defined outside in the global declaration section
extern int a; //This is a declaration
extern int a=42; //This is a definition
Related
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.
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.
I have a few doubts regarding the use of extern keyword with variables in C. I did go through the links related to this question. However, there are still a few things that I didn't gather very well
#include<stdio.h>
main( )
{
extern int i;
printf ( "\n%d ",i) ) ;
}
int i = 31 ;
In the above code, how does I get printed before its definition statement?
Now in the following code:
#include<stdio.h>
int x = 21 ;
main( )
{extern int i;
i=20;
printf ( "\n%d ", i ) ;
}
Isn't the statement "i=20;" a definition statement? I get an error for this. Is it because i'm trying to change the variable that is defined in some other source file? If this is the case how is the statement "int i=31;" in the top most code snippet right to use?
Also, I read, "int i;" is a definition. I don't really follow how.
In your first program, the print statement is printing the value of i based on the extern int i declaration. This is similar to calling a function based on its prototype declaration without seeing its definition. The compiler generates code to retrieve the value in the global variable named i. The symbol is resolved to the correct variable and address at link time.
In your second program, no definition for i is provided, only the extern int i declaration, and the attempt to set its value with i = 20. At link time this fails, since there is no definition, and so the attempt to resolve the reference to the global variable fails. Changing i = 20 to int i = 20 instead creates a local variable named i within the scope of the function main(), and is no longer referencing the globally declared extern int i.
When int i; is used at global scope, it is treated as a declaration and may be treated as a kind of definition. A global variable declared with an initializer, like:
int i = 20;
is always treated as a definition. Only one definition of this type is allowed, even if each is using the same initializer value. However,
int i;
is treated like a declaration. If more than one of these declarations appear, they are all treated as declarations of the same variable. At the same time, if no declaration with an initializer is present, this variable is implicitly defined with an initializer of 0, and the linker will be able to resolve references to it.
Declaration of a variable/function simply declares that the variable/function exists somewhere in the program but the memory is not allocated for them.
Coming to the definition, when we define a variable/function, apart from the role of declaration, it also allocates memory for that variable/function.
So in the 1st program, int i = 31 outside the main() defines the variable i. This variable is then merely declared as an extern variable inside the main(). Hence the program works.
In the 2nd program, without defining the variable i elsewhere, it is directly declared as an extern variable. Hence it gives an error.
In the second program you haven't defined the variable anywhere , not outside the main and instead you have defined it inside main so you are getting that error.
But in the first program you are defining the variable once and that is outside the main so you don't get that error.Program looks outside the main and find its definition.
int i; is a variable definition declaration both for AUTO variables (i.e inside main or any function ) but not for the external variables for extern variables you have to declare it like :
extern int i;
and then define outside main like this :
int i;
The idea behind extern is that you tell the compiler you're going to use a variable that was already defined outside the scope of where it is used.
It doesn't make much sense in your second case as there i is defined as a local variable.
If you were to define it as a global, like you do in the first case, it would be fine.
If I can demonstrate the use of extern with a very simple (contrived) case:
main.c:
#include <stdio.h>
extern int a; /* we tell the compiler that a will come from outside the scope of where it is used */
int main()
{
printf("%d\n", a);
return 0;
}
source.c:
int a = 3; /* we define a here */
You then compile both .c files like this:
$ gcc main.c source.c
This outputs 3.
You might also want to have a read at this article.
I am trying to understand this code:
#include<stdio.h>
int main()
{
extern int a;
printf("%d\n", a);
return 0;
}
int a=20;
When I run it, the value of a is 20. Yet this should be impossible, since the global variable a is defined at the bottom.
An extern declaration can only be used with variables that are global. It tells the compiler that the global variable is defined elsewhere, and asks the linker to figure it out.
In your code, extern int a refers to the a defined at the bottom of your example. It could have been equally well defined in a different translation unit.
As others have pointed out, the initialization of a takes place before main() is entered.
Not a problem. By declaring the variable as extern you are promising the linker it is defined else where part of current or other source files at global scope.
Initialization of global variables occurs before main() is called.
So even if the initialization a = 20 is located beneath the implementation of main(), it's always executed first, so it can be used at program start (assuming you fittingly declared the variable in scopes where it's to be used using extern int a).
After seeing this answer
I have this doubt.
In my project,
I have seen some extern variables declared and defined like below:
file1.h
extern int a;
file1.c
extern int a=10;
But in the link I mentioned it says that in the c file it should be defined like:
int a = 10;
Does adding extern key word during the definition too has any purpose/meaning.
Or does it matter by the way?
It does not change the meaning. extern only makes sense when you declare a variable. Defining a variable with extern is the same because all global variables that are not marked static are symbols visible to the linker by default.
Note that if you didn't want to initialise the variable, that is, not having the part = 10, the compiler will assume that extern int a is always a declaration and not a definition. In the same sense, having int a globally is always a definition and not just a declaration.
It depends. In this case, it makes no difference, but it can.
There are two issues here: definition vs. just declaration, and linkage.
And C++ doesn't handle them in an orthogonal manner. In C++, the
declaration of a variable or a reference is a definition if and only if
neither the extern keyword nor an initialization are present. (Note
that the rules are different for functions, types and templates.) So:
extern int a; // not a definition
int a; // definition
extern int a = 42; // definition
int a = 42; // definition
The rules say you must have exactly one definition, so you put a
definition in a source file, and the declaration in a header.
With regards to linkage, a symbol declared as a variable or a reference
has external linkage if it is declared at namespace scope, is not
declared static, and is either not const (nor constexpr in C++11)
or has been declared extern. The fact that const can give a
variable internal linkage occasionally means that the extern is
necessary:
int const a = 42; // internal linkage
extern int const a = 42; // external linkage
Note that the extern doesn't have to be on the same declaration:
extern int const a; // declaration, in header...
int const a = 42; // external linkage, because of
// previous extern
Still, I've occasionally needed the extern; typically because I want
to use a local constant to instantiate a template. (This is only an
issue if the template parameter takes a pointer or a reference. You can
instantiate a template with an int parameter with an int const a =
42;, because the template is instantiated with the value 42, and not
the variable a.)