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.
{
static int a; //no linkage
}
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.
{
static int a; //no linkage
extern int a; //a should get external linkage, no?
}
GCC error: extern declaration of a follows declaration with no linkage
Can somebody explain me why do I get this error?
Thank you
Your supposition is correct: the second declaration of a has external linkage. However, you get an error because your code violates a constraint in §6.7:
3 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, except for tags as
specified in 6.7.2.3.
That is, once you've declared a to have no linkage, you can't redeclare it again in the same scope.
A valid example of this rule being invoked is:
int a = 10; /* External linkage */
void foo(void)
{
int a = 5; /* No linkage */
printf("%d\n", a); /* Prints 5 */
{
extern int a; /* External linkage */
printf("%d\n", a); /* Prints 10 */
}
}
if the prior declaration specifies no linkage
means
if the prior declaration specifies not a sign of linkage
and not
if the prior declaration specifies that it has no linkage
This is confusing and ambiguous; not the usual way to write a standard...
Related
See the following code:
/* first file */
int i; /* definition */
int main () {
void f_in_other_place (void); /* declaration */
i = 0
return 0;
}
/* end of first file */
/* start of second file */
extern int i; /* declaration */
void f_in_other_place (void){ /* definition */
i++;
}
/* end of second file */
I know that external objects have external linkage and internal objects have none linkage(ignoring extern for a moment). Now if i talk about the function f_in_other_place(), it is declared inside main function. So will the identifier for it be treated as an internal object ? If yes than it should have none linkage but as visible in program this function refers to it's definition in second file which shows that identifier for it is behaving like an object with external linkage. So i am confused whether this identifier here has external linkage or none linkage ?
Now coming to the extern keyword, I read somewhere that function declaration implicitly prefixes extern. So even if i have not mentioned extern for this function identifier explicitly, will my function's identifier by default become an object with external linkage and scoped inside main() ? Please correct me if i am going in wrong direction.
I know that external objects have external linkage and internal
objects have none linkage
I think that by the term "internal objects" you mean objects declared in block scopes.
As for this declaration
int i; /* definition */
then it is a declaration. You may place several such declarations one after another like
int i; /* definition */
int i; /* definition */
int i; /* definition */
The compiler generates the so-called tentative definition of this variable at the end of the translation unit initializing it by zero.
As for the function declaration in main then according to the C Standard (6.2.2 Linkages of identifiers)
5 If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if it
were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
and
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 this function declaration in main
void f_in_other_place (void);
is equivalent to
extern void f_in_other_place (void);
As there is no previous function declaration in the file scope then this function has external linkage.
If for example in the file scope before main there would be a declaration with the keyword static like
static void f_in_other_place (void);
then the function declared in main would have internal linkage.
From this linkage reference:
external linkage. The identifier can be referred to from any other translation units in the entire program. All non-static functions, all extern variables (unless earlier declared static), and all file-scope non-static variables have this linkage.
[Emphasis mine]
It doesn't matter where you declare the function, it will always have external linkage.
The following compiles fine, using static only during declaration of function:
#include <stdio.h>
static int a();
int a(){
return 5;
}
int main(){
printf("%d\n", a());
return 0;
}
As a side note, same behaviour as above happens with inline functions, i.e only the declaration could have the keyword.
However the following fails, doing the same but on a variable:
#include <stdio.h>
static int a;
int a = 5;
int main(){
printf("%d\n", a);
return 0;
}
Getting thew error:
non-static declaration of 'a' follows static declaration.
What is with the difference?
This quote from the C Standard shows the difference )6.2.2 Linkages of identifiers)
5 If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if it
were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
So a function looks like it has the implicit storage specifier extern (but it does not mean that it has the external linkage opposite to an object identifier that in this case has the external linkage).
Now according to the following quote
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 function has the internal linkage due to its initial declaration with the storage specifier static.
As for the identifier of a variable then
7 If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
The resume from the above cited quotes is the following. If a function has no explicitly specified storage class specifier extern then its linkage is determined by a prior function declaration (if such a declaration exists). As for an identifier of object then in this case it has the external linkage. And if there is a prior declaration of the identifier with the internal linkage then the behavior is undefined.
Here is an extern and a static variable with same name. The output prints the static variable a=10. Why is there no syntax error and how would I access extern a if needed?
#include<stdio.h>
extern int a;
static int a=10;
main()
{
printf("%d\n",a);
}
The C standard allows the opposite, extern after static:
6.2.2 Linkages of identifiers....
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.
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.
At the same time it states:
7 If, within a translation unit, the same identifier appears with both internal and external
linkage, the behavior is undefined.
BTW, the C++ standard makes it explicit:
7.1.1 Storage class specifiers....
static int b; // b has internal linkage
extern int b; // b still has internal linkage
....
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
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.
I was shifting around the 'C' standard and I came across this:
$6.7.9.5:
If the declaration of an identifier has block scope, and the
identifier has external or internal linkage, the declaration shall
have no initializer for the identifier.
So my question is on the title. I would also like some examples if possible.
static int i; // internal linkage
void f() {
extern int i; // block-scope declaration; refers to i in global scope
// still internal linkage - see 6.2.2/4
}
It means the following
#include <stdio.h>
static int x = 1;
int main()
{
int y = 2;
{
extern int x;
printf( "x + y = %d\n", x + y );
}
}
Here inside main in internal block variable x has internal linkage and denotes the same variable x that is defined outside main.
However in this program
#include <stdio.h>
static int x = 1;
int main()
{
int y = 2;
int x = 3;
{
extern int x;
printf( "x + y = %d\n", x + y );
}
}
the variable x declared with specifier extern has the external linkage and it is not the same as variable x defined before main. The reason for this is that other local variable x hides the global variable x that is defined before main.
You should download a more recent version of the C Standard. Look for n1570.pdf, the latest draft of the C11 Standard. Its language is more explicit:
6.2.2 Linkages of identifiers
An identifier declared in different scopes or in the same scope more than once can be made to refer to the same object or function by a process called linkage. There are three kinds of linkage: external, internal, and none.
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.
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.
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.
If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
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.
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.