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.
Related
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.
According to C standard:
In the set of translation units and libraries that constitutes an entire program, each
declaration of a particular identifier with
external linkage
denotes the same object or
function. Within one translation unit, each declaration of an identifier with
internal
linkage
denotes the same object or function. Each declaration of an identifier with
no
linkage
denotes a unique entity.
In my example we have three separate declarations with each identifier having a different linkage.So why doesn't this work?
static int a; //a_Internal
int main(void) {
int a; //a_Local
{
extern int a; //a_External
}
return 0;
}
Error:
In function 'main':
Line 9: error: variable previously declared 'static' redeclared 'extern'
Why does compiler insist that I'm redeclaring instead of trying to access external object in another file?
Valid C++ example for reference:
static void f();
static int i = 0; // #1
void g() {
extern void f(); // internal linkage
int i; // #2 i has no linkage
{
extern void f(); // internal linkage
extern int i; // #3 external linkage
}
}
Both Clang and VC seem to be okay with my C example; only some versions of GCC (not all) produce the aforementioned error.
§6.2.2, 7 says:
If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
So, your program has undefined behaviour.
§6.2.2, 4 says that
extern int a; //a_External
has external linkage because the prior declaration visible in the scope int a; //a_Local has no linkage. But
static int a; //a_Internal
declares a with internal linkage. Hence, it's undefined per §6.2.2, 7.
The compiler is giving this error because inside the a_External scope, a_Internal is still accessible, thus you are redeclaring a_Internal from static to extern in a_External because of the name collision of a. This problem can be solved by using different variable names, for example:
static int a1; //a_Internal
int main(void) {
int a2; //a_Local
{
extern int a3; //a_External
}
return 0;
}
C standard says:
In the set of translation units each declaration of a particular
identifier with external linkage denotes the same entity (object or
function). Within one translation unit, each declaration of an
identifier with internal linkage denotes the same entity.
In the set of translation units we cannot have multiple distinct external entities with the same name, so the types of each declaration that denotes that single external entity should agree. We can check if types agree within one translation unit, this is done at compile-time. We cannot check if types agree between different translation units neither at compile-time nor at link-time.
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.
static int a; //a_Internal
int main(void) {
int a; //No linkage
{
extern int a; //a_External
}
return 0;
}
Here the previous declaration of identifier a has no linkage, so extern int a has external linkage. It means that we have to define int a in another translation unit. However GCC decided to reject this code with variable previously declared static redeclared 'extern' error, probably because we have undefined behavior according to C standard.
this is hard to explain in text, so I will give an example.
//f1.c
int a = 5;
int main()
{
printf("func2() output is: %i\n", func2() );
return 0;
}
//f2.c
static int a = 3
int func2()
{
extern int a;
return a;
}
When I compile and run this, I get 3, while I was expecting 5. Can anyone explain to me why I get 3? I would have thought that by using extern within the function, it wouldn't use the value of the static variable.
From n1256 §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.
So, extern within function scope means that the variable has external linkage by default, but if there's another visible definition, that definition is used instead.
The static class-modifier denotes that the variable will only be visible in this translation-unit (f2.c) By using extern for a, you only declared that variable, but not defined it. Yet, there was an a available in the translation-unit f2.c, so this one will be used.
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.
#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.