Discussion:
Why error "variable previously declared ‘static’ redeclared ‘extern’"?
A A
2014-07-07 13:04:32 UTC
Permalink
The following code gives me an error when trying to build with gcc-4.8:

#include <stdio.h>
#include <stdlib.h>

static int i5 = 30;

int main(void)
{
int i5 = 12;
printf("i5: %d\n", i5);
{
extern int i5;
printf("i5: %d\n", i5);
}

printf("i5: %d\n", i5);
exit(0);
}

main.c:11:14: error: variable previously declared ‘static’ redeclared ‘extern’

However, it compiles with clang 3.0. I don't understand what does GCC
want to tell me with this message. As far I know, `extern' must refer
to a variable defined with an internal or external linkage so it this
case it must refer to static i5, not i5 defined in the first line of
main(). I looked into C standard section 6.2.2 but found nothing that
would justify this error message. I know this is GCC mailing group so
don't take it personally but my current guess is that GCC is simply
overzealous and less smart than Clang, is that right?
Alec Teal
2014-07-07 14:19:17 UTC
Permalink
All wrong:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

Top of page 144.

GCC is basically saying "you said it was static, but here it is extern!"
which is a contradiction.

Clang probably doesn't look for it because ... well it's not a common
error, perhaps a linker error later in the build, there really is no
sensible thing to do if something that is supposed to be static suddenly
becomes extern, the two terms are mutually exclusive.

Alec
Jonathan Wakely
2014-07-07 14:52:19 UTC
Permalink
Post by Alec Teal
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
Top of page 144.
I don't think that page is relevant.

Try section 6.2.2 paragraphs 4 and 7.

The code has undefined behaviour, which means the compiler can issue a
diagnostic, or ignore it, or generate a binary with unexpected
results.

N.B. in C++ the code is not undefined, instead there are three
different objects called i5 with internal linkage, no linkage and
external linkage respectively (see the example in section 3.5 paragaph
6 in the C++ standard).
Alec Teal
2014-07-07 14:33:20 UTC
Permalink
Sorry for the repost, Thunderbird decided (or I have found a keyboard
shortcut) to remove all your text, so my post had no context!
Good
#include<stdio.h>
#include<stdlib.h>
static int i5 = 30;
There will be "global" i5 int somewhere in the program's memory BUT
the linker will not let (as it cannot see) this i5 symbol from any other
object file.
That is it has "internal linkage". Yes it says "static" which is an odd
choice of keyword
but it does not mean static for all to access, it means internal linkage.
Read Denis Ritchie's famous book, it talks about symbols and linkage.
int main(void)
{
int i5 = 12;
printf("i5: %d\n", i5);
{
extern int i5;
Why did you write this line? What are you trying to do? What this says is
"make the linkage of i5 external" meaning other objects can have i5
linked into
them. BUT you've already said i5 is internal, thus a contradiction.
printf("i5: %d\n", i5);
}
printf("i5: %d\n", i5);
exit(0);
}
main.c:11:14: error: variable previously declared ‘static’ redeclared ‘extern’
Exactly. This error is one of the most useful I've seen from GCC in a while
(I get a lot of template onces.... they are long and cryptic)
Look up linkage
However, it compiles with clang 3.0. I don't understand what does GCC
Report the failure to them.
want to tell me with this message. As far I know, `extern' must refer
to a variable defined with an internal or external linkage so it this
case it must refer to static i5, not i5 defined in the first line of
main(). I looked into C standard section 6.2.2 but found nothing that
would justify this error message. I know this is GCC mailing group so
don't take it personally but my current guess is that GCC is simply
overzealous and less smart than Clang, is that right?
Have you heard of "Stackoverflow.com" I think it is, they can help
people like you. I also think you should read
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf cover to cover.

Two last questions, spawned by my curiosity:

Why did you put that extern inside the function body? Are you trying to
redefine symbols?
The name should really be unique, the name is what identifies a symbol.
Look at the symbol tables
from objdump, in C code they're not mangled, in C++ they are so
functions that have the same name
but take different arguments have UNIQUE link symbols.

To learn a language you should really try and make actual useful things
in it that do a task, not one file bits of tat that tests how pedantic a
compiler is, and how good the writers of it are to catch the most
obscure error only a select few will ever cause.

Alec
A A
2014-07-07 15:51:57 UTC
Permalink
Post by Alec Teal
Sorry for the repost, Thunderbird decided (or I have found a keyboard
shortcut) to remove all your text, so my post had no context!
Good
#include<stdio.h>
#include<stdlib.h>
static int i5 = 30;
There will be "global" i5 int somewhere in the program's memory BUT
the linker will not let (as it cannot see) this i5 symbol from any other
object file.
That is it has "internal linkage". Yes it says "static" which is an odd
choice of keyword
but it does not mean static for all to access, it means internal linkage.
Read Denis Ritchie's famous book, it talks about symbols and linkage.
int main(void)
{
int i5 = 12;
printf("i5: %d\n", i5);
{
extern int i5;
Why did you write this line? What are you trying to do? What this says is
"make the linkage of i5 external" meaning other objects can have i5
linked into
them. BUT you've already said i5 is internal, thus a contradiction.
"you've already said i5 is internal" - what i5 are you talking about
here - the one defined with `static' or the one defined in the first
line of main()? The former has internal linkage but latter has no
linkage if I understand standard correctly:

6.2.2 p. 6:

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 I guess you must be talking about i5 defined with `static' outside
main(). But even on page 144 of C standard you mentioned it is legal
to use `extern' to a variable with internal linkage so I don't really
understand your point. Where is the contradiction? If I understand
standard correctly there is no way to use `extern' to refer to a
variable with no linkage. I tried to use `extern' on a variable
defined inside function in this way and both Clang and GCC failed at
linking stage:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int a = 10;
{
extern int a;
printf("%d\n", a);
}
}

As such, `extern' cannot refer to i5 defined inside main() but only to
static i5. After removing a definition of i5 in the first line of
main() this code compiles correctly also in GCC. I think that GCC
could notice that and do the same thing as Clang but it doesn't, for
some reason, probably because this is the way it is designed.

By the way, output of program from my 1st post after compiling it with
Clang is:

i5: 12
i5: 30
i5: 12

And why do I this - after a few years of using C I feel I need to
enhance my knowledge on linkage vs scope vs duration and other
issues. I want to know how C really works, not only write code that
'somehow' works. I picked `static' keyword to study because I know it
has dual meaning in C and I want to understand what it really means. I
write small programs like this to check my understanding of C
standard. I have started reading C standard on my own a weeks ago and
although I slowly dive into strict technical English I realize that I
still don't understand a half of it. In such situations, when you
really want to understand something deeply it makes you frustrated
when two leading compilers give you answers that are mutually
exclusive. You start to wonder - is that you, the way one compiler
works and another doesn't, compiler bug, obsolete version of standard
you are reading (maybe C11 feature?), undefined or implementation
defined behavior. You are lost and you ask question on GCC mailing
group. That's it.
Jonathan Wakely
2014-07-07 16:05:24 UTC
Permalink
Post by A A
Post by Alec Teal
Sorry for the repost, Thunderbird decided (or I have found a keyboard
shortcut) to remove all your text, so my post had no context!
Good
#include<stdio.h>
#include<stdlib.h>
static int i5 = 30;
There will be "global" i5 int somewhere in the program's memory BUT
the linker will not let (as it cannot see) this i5 symbol from any other
object file.
That is it has "internal linkage". Yes it says "static" which is an odd
choice of keyword
but it does not mean static for all to access, it means internal linkage.
Read Denis Ritchie's famous book, it talks about symbols and linkage.
int main(void)
{
int i5 = 12;
printf("i5: %d\n", i5);
{
extern int i5;
Why did you write this line? What are you trying to do? What this says is
"make the linkage of i5 external" meaning other objects can have i5
linked into
them. BUT you've already said i5 is internal, thus a contradiction.
"you've already said i5 is internal" - what i5 are you talking about
here - the one defined with `static' or the one defined in the first
line of main()? The former has internal linkage but latter has no
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.
Paragraph 4 says the "extern int i5" has external linkage, because the
prior declaration (the first one in main) has no linkage. So you've
declared i5 to have both internal linkage (the first declaration of
i5) and external linkage (the third declaration of i5) and paragraph 7
says that is undefined.
Post by A A
So I guess you must be talking about i5 defined with `static' outside
main(). But even on page 144 of C standard you mentioned it is legal
to use `extern' to a variable with internal linkage so I don't really
understand your point. Where is the contradiction? If I understand
standard correctly there is no way to use `extern' to refer to a
variable with no linkage. I tried to use `extern' on a variable
defined inside function in this way and both Clang and GCC failed at
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a = 10;
{
extern int a;
printf("%d\n", a);
}
}
As such, `extern' cannot refer to i5 defined inside main() but only to
static i5.
But you've re-declared it with different linkage.
Post by A A
After removing a definition of i5 in the first line of
main() this code compiles correctly also in GCC.
Because by 6.2.2 p4 the prior declaration is the one at file scope,
and the re-declaration has the same linkage. The difference is which
prior declaration is visible.
Post by A A
I think that GCC
could notice that and do the same thing as Clang but it doesn't, for
some reason, probably because this is the way it is designed.
You're saying GCC should have particular behaviour for something which
is undefined behaviour. That's not how undefined behaviour works.

You should fix your program.
Post by A A
By the way, output of program from my 1st post after compiling it with
i5: 12
i5: 30
i5: 12
And why do I this - after a few years of using C I feel I need to
enhance my knowledge on linkage vs scope vs duration and other
issues. I want to know how C really works, not only write code that
'somehow' works. I picked `static' keyword to study because I know it
has dual meaning in C and I want to understand what it really means. I
write small programs like this to check my understanding of C
standard. I have started reading C standard on my own a weeks ago and
although I slowly dive into strict technical English I realize that I
still don't understand a half of it. In such situations, when you
really want to understand something deeply it makes you frustrated
when two leading compilers give you answers that are mutually
exclusive. You start to wonder - is that you, the way one compiler
works and another doesn't, compiler bug, obsolete version of standard
you are reading (maybe C11 feature?), undefined or implementation
defined behavior. You are lost and you ask question on GCC mailing
group. That's it.
And the answer to your question is that the standard says it's
undefined behaviour.

Loading...