Use of 'extern' keyword while defining the variable - c

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.)

Related

understanding of extern storage class [duplicate]

This question already has answers here:
What is the difference between a definition and a declaration?
(27 answers)
Closed 5 years ago.
Can you please someone explain me the flow of below problem,
#include <stdio.h>
int main(){
extern int a;
printf("%d\n",a);
return 0;
}
int a = 20;
and the output is 20. I am not sure where is the variable a getting defined and where is it getting declared?
The variable a is declared and defined as a global variable in the line:
int a = 20;
The extern line just tells the main() function scope that a is defined in another place.
In this case, the use of extern is not really necessary. You could just declare and define a before the main() function, and then main() would be familiar with it.
Usually, you would use extern when you want to use a variable or a function that was defined in another source file (and not just later in the same source file).
The C programming language has been designed to be one-pass, so that the compiler could process each line only once from top to bottom. So considering your program:
#include <stdio.h>
int main(){
extern int a;
printf("%d\n",a);
return 0;
}
int a = 20;
The identifier a is declared twice, and defined once.
Before the 4th line extern int a;, the compiler doesn't know anything about the identifier a. The declaration extern int a; has the block scope within the function main, and it declares the identifier a as an int and that its storage duration is static and linkage is external. So the compiler can write code that access a global identifier by name a as an int variable that could be defined in another module (external linkage). This is what the compiler does on line 5 when it is used in printf.
Finally at line 9, int a = 20; is another declaration and definition. This declares and defines a as a int with static storage duration, and external linkage.
If you'd put the int a = 20; before the main, the declaration extern int a; would be useless, because it doesn't add anything. I tend to put my main and other depending functions last in my source code, so that minimal amount of extra declarations are needed.
extern is syntactically a "storage class" keyword. But there is no such storage class. C has "static storage", "dynamic storage (malloc, etc) and "automatic storage" (local variables, usually represented using a stack).
If an identifier is declared extern inside a block scope, it means that the declaration refers to an external definition. If the entity being declared is an object, then it has static storage, simply because external objects have static storage. It can be a function too; functions aren't said to have storage.
In C, there is a concept called "linkage". Objects declared outside of any function at file scope, and functions, can have "external" or "internal" linkage.
If we have extern in a block scope, as you have in the example program, there can be a prior declaration of the same name at file scope, or in a nested scope, like this:
static int x;
/* ... */
{
extern int x;
}
Here, the inner x refers to the outer x, and, in spite of being "extern", it has internal linkage because of the "static".
In a nutshell, extern usually means "refer to the earlier declaration, and if there isn't one, declare this as an identifier with external linkage".
The word "external" refers to two separate concepts: the aforementioned "external linkage" and also to the meaning "outside of any function", as in "external declaration". Confusingly, "external declarations", like the static int x above, can have "internal linkage"!
In your program, things are correct because the block scope extern declaration of a and the later int a = 20, which are in separate scopes, happen to independently agree with each other.
The int a = 20; is an external declaration, which is also an external definition (because of the initializer). Since in that scope, no prior declaration of a is visible, it gets external linkage.
So, where is a defined? It is defined as an object with external linkage, in the entire translation unit as a whole. That translation unit is what defines a. a is declared in every place of the program where a declaration appears; and its definition is also a declaration. It is declared in main and also in the last line of the translation unit's source code.
A "declaration" is syntax which makes a name known in some scope. It's a concept that is active during the translation of a program. A "definition" is the fact that some object or function is provided in some translation unit. Translated units still provide definitions, but need not retain information about declarations. (Which is why when we make libraries, we provide header files with declarations in them!)
From the point of view of your main function, that function doesn't "care" where a is defined. It has declared a in such a way that if a is used, then an external definition of a, with external linkage, must exist. That definition could come from anywhere: it could be in the same translation unit, or in another translation unit.
When ever you declare a variable as extern then It means that Variable is declared as global and you cannot initialize the variable there.Because no memory is allocated for that variable It is just declared as a Variable
you can define it some where in your code.
Let us take an example ..consider the code
int main()
{
extern int i;
i=10;
printf("%d",sizeof(i));
}
here you get an error that int 'i' is not defined
therefore you need to write it as:
int main()
{
extern int i;
int i=10;
printf("%d",sizeof(i));
}
In case of your code:
This is declaration
extern int a;
This is definition:
int a = 20;
The storage class extern specifies storage duration and linkage of the object the identifier refers to:
The storage duration is set to static, which means the variable is alive for the whole time the program runs. As you declare that variable inside a function scope, this matters in your example, because in function scope, the default storage duration would be automatic.
The linkage is set to external, this just means different translation units of the same program can share the object. It has the side effect that a definition in another (file) scope is acceptable, as shown in your example. This is a logical consequence of the shared nature, you would typically declare a variable with external linkage in all translation units using it, but define it only in one.

Storage class declarations

Are the following declarations correct?
Outside any function:
int a; //external by default
extern int a; //explicitly extern
static int a; //explicity static
const int a; //static by default
static const int a; //explicitly static
extern const int a; //explicitly extern
Inside a function:
int a; //auto by default
static in a; //explicity static
const int a; //static by default
static const int a; //explicitly static
Close.
Anything at global scope (ie: outside a function) is static by default.
eg:
//main.c
int myVar; // global, and static
int main(void) {
...
return 0;
}
//morecode.c
extern int myVar; //other C files can see and use this global/static variable
However, if you explicitly declare something at the global scope as static, not only is it static, but it is only visible inside that file. Other files can't see it.
//main.c
static int myVar; // global, and static
int main(void) {
...
return 0;
}
//morecode.c
extern int myVar; // compiler error; "myVar" can only be seen by
// code in main.c since it was explicitly
// declared static at the global scope
Also, nothing is "extern" by default. You typically use extern to access global variables from other files, provided they weren't explicitly declared static as in the example above.
const only implies that the data cannot change, regardless of it's scope. It does not imply extern, or static. Something can be "extern const" or "extern", but "extern static" doesn't really make sense.
As a final example, this code will build on most compilers, but it has a problem: myVar is always declared "extern", even in the file that technically creates it. Bad practice:
//main.c
extern int myVar; // global, and static, but redundant, and might not work
// on some compilers; don't do this; at least one .C file
// should contain the line "int myVar" if you want it
// accessible by other files
int main(void) {
...
return 0;
}
//morecode.c
extern int myVar; //other C files can see and use this global/static variable
Finally, you might want to cover this post on the various levels of scope if you are not already familiar with them. It will likely be helpful and informative to you. Good luck!
Terminology definition - Scope in C application
The person who answered this question of mine on scope did a good job, in my opinion.
Also, if you declare something static within a function, the value remains between function calls.
eg:
int myFunc(int input) {
static int statInt = 5;
printf("Input:%d statInt:%d",input,statInt);
statInt++;
return statInt;
}
int main(void) {
myFunc(1);
myFunc(5);
myFunc(100);
return 0;
}
Output:
Input:1 statInt:0
Input:5 statInt:1
Input:100 statInt:2
Note that the use of a static variable within a function has a specific and limited number of cases where they are useful, and generally aren't a good idea for most projects.
One misconception you have appears to be that extern is the opposite of static. This is not the case. You have this:
int a; //extern by default
That's not "extern by default". An extern declaration means that the actual variable definition is elsewhere. So if you have this in your source file:
extern int a;
Then somewhere else you have another source file with:
int a;
Otherwise, if you compile your code you'll get:
/tmp/cc3NMJxZ.o: In function `main':
foo.c:(.text+0x11): undefined reference to `a'
collect2: ld returned 1 exit status
static outside of a function definition means that the variable is only visible to other code defined in the same file. The absence of static means that the variable is visible globally to code that might link against your object file.
I am less certain, but I don't believe that const implies static. That shouldn't be too hard to test.
...and indeed, a very simple test confirms that const does not imply static.
You have to separate the concepts of storage duration and linkage. extern and static, in various contexts, can have effects on both of these properties and other effects but aren't the sole determiner of any of them.
At file scope
int a;
This is a tentative definition. a has static storage duration and external linkage.
extern int a;
A declaration but not a definition. static storage duration and external linkage (or the linkage determined by a prior declaration if one is visible).
static int a;
A tentative definition. static storage duration and internal linkage.
const int a;
A tentative declaration. static storage duration and external linkage (unlike C++).
static const int a;
A tentative definition. static storage duration and internal linkage.
extern const int a;
A declaration and not a definition. static storage duration and external linkage (or the linkage determined by a prior declaration if one is visible).
In block scope
int a;
Definition. automatic storage duration and no linkage.
static int a;
Definition. static storage duration and no linkage.
const int a;
Definition. automatic storage duration and no linkage.
(I think this is strictly legal but not very useful as you can't modify a's indeterminate initial value without causing undefined behavior.)
static const int a;
Definition. static storage duration and no linkage.
(Again, not very useful!)

What is the use of declaring a static variable as extern inside a function?

#include <stdio.h>
static i = 5;
int main()
{
extern int i;
printf("%d\n",i);
return 0;
}
Can someone give any use-case for declaring a static variable as extern inside a function block?
NEW:
Why is this not allowed?
int main()
{
static i = 5;
extern int i;
printf("%d\n",i);
return 0;
}
this is useful when you need to access a variable that resides within another translation unit, without exposing the external variable globally (for a few reasons, like name collision, or that the the variable shouldn't be directly accessed, so static was used to limit its scope, but that TU's header still needs access).
As an example, lets say we have a translation unit foo.c, it contains:
//foo.c
static int i = 0;
i shouldn't be changed or directly accessed outside foo.c, however, foo.h comes along requiring access to i for an inline function, but i shouldn't be exposed to any translation unit using foo.h, so we can use extern at functional level, to expose it only during the scope of IncI, the inline function requiring the use of i:
//foo.h
inline void IncI(int val)
{
extern int i;
i += val;
}
Your second example is 'disallowed' because the compiler thinks you are trying to bind two different variables to the same symbol name, ie: it creates the static i at local scope, but searches for the extern int i at global scope, but doesn't find it, because static i as at the function scope. a more clever compiler would just fix the linkage to the static i, whether or not this follows standards I wouldn't know.
Now that I have a C standards document to work from (shame on me I know...), we can see what the official stance is (in C99):
6.2.2 Linkages of identifiers
Section 3:
If the declaration of a file scope identifier for an object or a function contains the storageclass
specifier static, the identifier has internal linkage.
Section 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.
thus, because static will cause internal linkage, the extern will bring that linkage into the current scope. there is also a footnote stating that this may cause hiding of variables:
23) As specified in 6.2.1, the later declaration might hide the prior declaration.
In your second case, you are telling the compiler you have a static (local) variable i and another (global) variable i that is defined somewhere else.

Difference between extern int a; extern int a=42;

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

Doubt related to extern keyword usage

AFAIK, extern keyword should be used for declaration and no value can be associated with the variable being declared with extern keyword. But supposing I write a statement like
extern int i = 10;
Should the compiler flag an error for the same? I have seen some compilers being tolerant and ignoring this? Why is this so? What does the 'C' standard says about this?
EDIT: #All, Thanks for the answers. I have a doubt still though. Suppose I have the definition for this variable without the extern linkage in another file say a.c and I add this statement in b.c. Still is it Ok for the compiler not to flag an error? Does it come under redefintion?
That's valid syntax, there is even an essentially identical example in the C99 standard. (See ยง6.9.2-4.)
It's true that the examples are not normative but I believe it was intended to be legal syntax. The compiler will often output a warning, because it doesn't really accomplish anything.
4 EXAMPLE 1
int i1 = 1; // definition, external linkage
static int i2 = 2; // definition, internal linkage
extern int i3 = 3; // definition, external linkage
int i4; // tentative definition, external linkage
static int i5; // tentative definition, internal linkage
int i1; // valid tentative definition, refers to previous
int i2; // 6.2.2 renders undefined, linkage disagreement
int i3; // valid tentative definition, refers to previous
int i4; // valid tentative definition, refers to previous
int i5; // 6.2.2 renders undefined, linkage disagreement
extern int i1; // refers to previous, whose linkage is external
extern int i2; // refers to previous, whose linkage is internal
extern int i3; // refers to previous, whose linkage is external
extern int i4; // refers to previous, whose linkage is external
extern int i5; // refers to previous, whose linkage is internal
The following code ;
extern int i ;
declares a variable i, but does not instantiate it. If it is not also defined in the same compilation unit, the linker will attempt to resolve it from the object files and libraries that comprise the final executable.
However your example:
extern int i = 10 ;
initialises the object, and therefore must also instantiate it. In this case the extern keyword is redundant because the object is initialised in the same compilation unit (in fact the same statment). It is equivalent to:
extern int i ; // redundant
int i = 10 ;
Although in this last example the extern keyword is redundant, it is exactly equivalent to what you have when a global variable is declared in a header file, and instantiated in a source file that also includes that header (as it should, to allow the compiler to perform type checking).
You can test this as follows:
extern int i ;
int main()
{
i = 10 ;
}
The above will cause a linker error for unresolved variable i. Whereas:
extern int i = 10 ;
int main()
{
i = 10 ;
}
will link without problem.
The extern keyword indicates that the given variable is allocated in a different module. It has nothing to do with access to that variable. It's perfectly legal to assign to assign to an extern variable.
The purpose of extern keyword is to give the entity external linkage. Whether it is used in a declaration in a or definition makes no difference. There's absolutely no error in the code you posted.
If you prefer to think about it in terms of "export vs. import", then extern keyword applied to a non-defining declaration means that we are importing an entity defined in some other translation unit. When extern keyword applied to a definition, it means that we are exporting this entity to be used by other translation units. (Although it is worth noting that "export vs. import" is not exactly a standard way of thinking about the concept of C linkage.)
The reason you won't see the keyword used in definitions very often is because in C file-scope definitions have external linkage by default. So writing
extern int i = 10;
is valid, but redundant, since it is equivalent to plain
int i = 10;
Yet, from time to time in the actual code you might see people using this keyword with function declarations and definitions, even though it is superfluous there as well
extern void foo(int i); /* `extern` is superfluous */
...
extern void foo(int i) /* `extern` is superfluous */
{
/* whatever */
}

Resources