Doubt related to extern keyword usage - c

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 */
}

Related

Order of `static` definition and `extern declaration` in a translation unit

I am unable to understand why this doesn't work.
extern int i;
int main()
{
printf(" %d ", i);
}
static int i =3;
Also, this doesn't work:
extern int i;
static int i =3;
int main()
{
printf(" %d ", i);
}
But if static variable is defined before the extern declaration it works:
static int i =3;
extern int i;
int main()
{
printf(" %d ", i);
}
As I understand from extern int itells that i is present somewhere else and here how it looks lik(int i)
But, somewhere else means:
1) Maybe, later point in the same translation unit as a global variable.
2) Maybe, in some other translational unit.
I was thinking that (1) would be valid even though static int i = 3 has restricted i's scope to the current translation unit where it is defined.
Isn't static int i =3 global( i mean atleast it is visible in the translation unit) here even though it has the restricted scope to its translation unit? Then why isn't compiler unable to find it?
When I compile the first two versions I get the following compile time error:
error: static declaration of ‘i’ follows non-static declaration
note: previous declaration of ‘i’ was here
I am unable to understand this error message. Also, why it is complaining it as a static declaration isn't it a definition also?
C11 6.2.2 Linkages of identifiers 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,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.
So the second declaration will follow the first, back to your examples, the 1st and 2nd example i will have an extern storage-class. The compiler thinks that's an error.
While in the 3rd example, i will be static because static shows first. That should be no problem.
And, in the Section 7 of C11 6.2.2 Linkages of identifiers
If, within a translation unit, the same identifier appears with both internal and external
linkage, the behavior is undefined.
So it's better not to declare the same variable with both static and extern in the same translation unit.
Well, a variable is either extern or static. Remember that static at a global level restricts its visibility only to the current translation unit, whereas extern dictates that it is visible across different translation units.
It makes no sense to declared something as static and again as extern. Doing so is undefined behaviour, so don't do it.

static declaration of m follows non-static declaration

I am trying a small example to know about the static external variable and its uses. The static variable is of local scope and the external variable is of global scope.
static5.c
#include<stdio.h>
#include "static5.h"
static int m = 25;
int main(){
func(10);
return 0;
}
static5.h
#include<stdio.h>
int func(val){
extern int m;
m = m + val;
printf("\n value is : %d \n",m);
}
gcc static5.c static5.h
o/p :
static5.c:3: error: static declaration of m follows non-static declaration
static5.h:3: note: previous declaration of m was here
EDITED
The correct program :
a.c:
#include<stdio.h>
#include "a1_1.h"
int main(){
func(20);
return 0;
}
a1.h:
static int i = 20;
a1_1.h:
#include "a1.h"
int func(val){
extern int i;
i = i + val;
printf("\n i : %d \n",i);
}
This works fine perfectly fine. But this is compiled into a single compilation unit. Hence could able to access the static variable . Across the compilation unit we cannot use the static variable by using the extern variable.
static has a very simple logic to it. If a variable is static, it means that it is a global variable, but it's scope is limited to where it is defined (i.e. only visible there). For example:
Outside a function: global variable but visible only within the file (actually, the compilation unit)
Inside a function: global variable but visible only within the function
(C++) Inside a class: global variable but visible only to the class
Now let's see what the C11 standard says regarding static and extern (emphasis mine):
6.2.2.3
If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
6.2.2.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.
6.2.2.7
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
So the standard says that first, if you have:
static int m;
extern int m;
then the second declaration (with extern) would regard the first one and in the end m would still be static.
However, in any other case, if there are declarations with both internal and external linkage, the behavior is undefined. This actually leaves us with only one option:
extern int m;
static int m;
i.e., extern declaration before static declaration. gcc was nice enough to give you error in this case of undefined behavior.
Remember this (quoting Eli Bendersky):
A static variable inside a function keeps its value between
invocations.
A static global variable or a function is "seen" only in
the file it's declared in
In your code, static int m = 25; means that m's scope is limited only to that file, that is, it is only visible inside static5.c and nowhere else.
If you would like to make use of m outside of static5.c make sure to remove the keyword static from the declaration of the variable.
For a more canonical explanation, along with an example, see this answer by Eli Bendersky
EDIT: (according to Klas' recommendation) **The actual scope is a compilation unit, not the source file. The compilation unit is the way the file looks after the preprocessor step
The problem is exactly as stated in the error message. m is declared a normal int but is later defined as a static int.
extern tells the compiler/linker to look for the variable in the global table of variables.
static (outside a functon) tells the compiler to exclude the variable from the global table of variables.
Do you see the conflict?
To fix the problem, either remove the static keyword from the definition or move the definition above the inclusion of static5.h.
It should be noted that the way you have designed your files is not considered best practice. Include files don't usually contain functions.
remove the keyword static while declaring m and the errors will be removed and you will be able to get the answer as 50. The static keyword makes the scope to restrict within the file.

External variable declaration and definition

a)The definition of an external variable is same as that of a local variable,ie, int i=2; (only outside all functions).
But why is extern int i=2; too working as the definition? Isn't extern used only in variable declaration in other files?
b)file 1
#include<stdio.h>
int i=3;
int main()
{
printf("%d",i);
fn();
}
file2
int i; // although the declaration should be: extern int i; So, why is this working?
void fn()
{
printf("%d",i);
}
OUTPUT: 3 in both cases
For historical reasons, the rules for determination of linkage and when a declaration provides a definition are a bit of a mess.
For your particular example, at file scope
extern int i = 2;
and
int i = 2;
are equivalent external definitions, ie extern is optional if you provide an initializer.
However, if you do not provide an initializer, extern is not optional:
int i;
is a tentative definition with external linkage, which becomes an external definition equivalent to
int i = 0;
if the translation unit doesn't contain another definition with explicit initializer.
This is different from
extern int i;
which is never a definition. If there already is another declaration of the same identifier visible, then the variable will get its linkage from that; if this is the first declaration, the variable will have external linkage.
This means that in your second example, both file1 and file2 provide an external definition of i, which is undefined behaviour, and the linker is free to choose the definition it likes best (it may also try to make demons fly out of your nose). There's a common extension to C (see C99 Annex J.5.11 and this question) which makes this particular case well-defined.
In C, an extern with an initialization results in a variable being allocated. That is the declaration will be considered a defining declaration. This is in contrast with the more common use of extern.
The C standard says:
6.9.2 External object definitions
.....
If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
As for the second part of your question, your declaration int i at file scope has external linkage. If you want to give it internal linkage you need to declare it static int i. The C standard says:
6.2.2 Linkages of identifiers
......
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

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.

Use of 'extern' keyword while defining the variable

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

Resources