Reputation: 411
Code:
typedef int a; // #1
extern int a; // #2, error
gcc will generate an error "'a' redeclared as a different kind of symbol", but when we move the extern
declaration to block scope, there will be no warning, why?
typedef int a; // #3
void foo() {
extern int a; // #4, ok
}
And:
char a; // #5
void foo() {
extern int a; // #6, error
}
Update:
Thanks for @Yunnosch's reply, but it still can not answer my question. Let's look at #6,#5, when the compiler sees #6, it will try to lookup in the file scope identifiers to find if the same 'a' exists, although they are in different scopes, the compiler generates an error.
Then looking at #4,#3, when the compiler sees #4, it will find the same 'a' exists in the same way, why doesn't it generate an error?
@Yunnosch and @Stargateur both explain it something about different scopes, it's obviously not true. My view is it's something about linkage, but #2 cannot hide #1 telling me it's also not true.
Update 2:
Thanks for @AnT, he gave a very detailed explanation.
Upvotes: 1
Views: 165
Reputation: 320611
Both typedef names and variable names are ordinary identifiers in C. They share the same name space. You can't have two identically-named declarations that declare different entities in the same scope and the same name space
6.2.1 Scopes of identifiers
2 [...] Different entities designated by the same identifier either have different scopes, or are in different name spaces.[...]
Also, as suggested by Stefan Ram in comp.lang.c 6.7/3 might be even more relevant here
6.7 Declarations
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 that:
— a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
— tags may be redeclared as specified in 6.7.2.3.
In either case, the key point is that both of your declarations are made in same scope and same name space. This is the requirement(s) that is(are) violated by your first code sample. This is what the compiler is complaining about.
Your second and third code samples declare two identifiers a
in different scopes. There's no violation of 6.2.1/2 there. These examples might suffer from other issues, but that's a completely different story.
Your second example might be perfectly valid, provided you define the global a
in a different translation unit (in a different file scope), where its definition won't conflict with the typedef declaration.
Your third example leads to undefined behavior, since external definition of a
specifies a type that is not compatible with the local extern
declaration.
6.2.7 Compatible type and composite type
2 All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
Upvotes: 1
Reputation: 26753
C compilers do not like to see conflicting symbol definitions within a scope,
but do not mind if a conflict occurs only across different scopes.
For example, exaggerating by even using the same kind of symbol:
example 1: basic, warning free, error free
#include <stdio.h>
int a=0;
int main()
{
printf("%d\n", a);
return 0;
}
example 2: conflict same scope
#include <stdio.h>
int a=0;
int a=5; // main.c 3 error: redefinition of 'a'
int main()
{
printf("%d\n", a);
return 0;
}
example 3: different scopes conflict free
#include <stdio.h>
int a=0;
int main()
{
{
int a=5;
printf("%d\n", a);
}
printf("%d\n", a);
return 0;
}
In example 3, the "inner" a
, with value 5, hides the outer a
.
The value 5 is happily printed from withing the inner scope, it hides the outer a
.
Then, when the inner scope is left, the outer value 0 is happily printed. It is not hidden by the inner scope anymore.
In your 1st case, the conflict arises between two a
s (in your case of different types), when they are in same scope, like in my example 2.
In your 2nd case, the two a
s are in two different scopes and do not conflict.
My example 3 shows, that in that case they would not even conflict if they were the same type AND same identifier.
example 4: conflicting types between global and extern local (swapped types, to continue the example sequence)
#include <stdio.h>
int a=0;
int b=1;
static int c=10;
void foo() {
extern int b;
extern char a; // main.c 8 error: conflicting types for 'a'
extern char c; // main.c 9 error: conflicting types for 'c'
}
int main()
{
{
int a=5;
printf("%d\n", a);
}
printf("%d\n", a);
return 0;
}
In example 4, based on your question-edit, the extern
tells the compiler to use an a
which has been defined elsewhere, explicitly telling it to use it in this function scope, too.
The compiler has however already seen a definition of a
and (assuming it is the only one, because it would otherwise be a redefinition) it complains about the different types. Note the different error, "conflicting types" instead of "redefinition".
In contrast to that, note that the similar line above, with b
, does not conflict. The compiler is told to know about a b
, to be found elsewhere, with identical type. That is found in the outer global scope.
Using static
, to make a symbol file-only scope insteadd of global, does not change this, the example uses c
to demonstrate. The external c
is still identified to be the conflicting c
with different type, defined at this files scope.
Upvotes: 0
Reputation: 1
If a file-scope object or a function does not need to be visible outside of the file, it should be hidden by being declared as static. This practice creates more modular code and limits pollution of the global name space.
Upvotes: 0