Redeclaration of 'x' with no linkage [duplicate] - c

This question already has answers here:
Redeclaration of global variable vs local variable
(3 answers)
Closed 2 years ago.
This code works fine when I re-declare the variable x in global scope:
#include <stdio.h>
#include <stdlib.h>
int x = 12;
int x;
int main() {
printf("%d", x);
return 0;
}
However, this code gives me an error: "redeclaration of 'x' with no linkage"
#include <stdio.h>
#include <stdlib.h>
int main() {
int x = 12;
int x;
printf("%d", x);
return 0;
}
I have learned that redefinition is not allowed more than once but redeclaration is allowed. Is this true only for global variables?

The rules around linkage and declaration are complicated and hard to summarize. In part, they developed over time, and the rules had to accommodate old software written with old rules.
The relevant rule in this case is in C 2018 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 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.
Your identifier is not a typedef name or a structure or union tag, and it has no linkage because it is declared inside a block without extern, so there shall be no more than one declaration of it in that scope.

Related

c - static and extern one again

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.

extern in block scope does not conflct with typedef in file scope?

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.
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.
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.
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 as (in your case of different types), when they are in same scope, like in my example 2.
In your 2nd case, the two as 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.

Global variable declaration in c [duplicate]

This question already has answers here:
Tentative definitions in C and linking
(3 answers)
Closed 6 years ago.
#include<stdio.h>
int check,check;
void main(){
printf("Hello!!");
}
When I compile this piece of code, everything goes on normal but when I give this inside the main function,
#include<stdio.h>
void main(){
int check,check;
printf("Hello!!");
}
I get an error like
C:\MinGW\bin>cc ex1.c
ex1.c: In function 'main':
ex1.c:4:11: error: redeclaration of 'check' with no linkage
int check,check;
^
ex1.c:4:5: note: previous declaration of 'check' was here
int check,check;
^
Why is it so?
This is possible in global scope, because that is considered an tentative definition.
Quoting C11, chapter §6.9.2
A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition.
However, in the block scope (function scope), there's no tentative definition, hence the code tries to create two identifiers with the same name which is cause for the re-declaration error, because they actually denote the same object.
You can read more about it here.
That said, since C99, for hosted enviroments, void main() is not a valid signature anymore, it has to be int main(void) at least.

Declaration and Definition issue

I know this question has been asked many times,but I don't find any relevant answer.
According to C
int x; //definition
extern int x; //declaration
int func(void); //declaration
int func(void) //definition
{
}
My first question is if int x is definition,then why compiler shows an redeclaration error
header files
int main()
{
int x,x; //for this it shows redeclaration error
}
And my second question is if I am defining the var x,twice it doesn't show any error
header files
int x;
int x;
int main()
{
}
I am using window 7 and DevCpp 5.6.2
Edited :
header files
int y;
int main()
{
int x;
}
x and y are definition here?
A declaration of a variable of at file scope without an initializer (and without storage class specifier) is a tentative definition:
int i;
It is valid to have multiple tentative definitions of the same variable in the same source file:
int i;
int i;
the behavior specified by C is as if there is a declaration at the top of the source file and at the end of the source file there is a int i = 0;.
At block scope there is no tentative definition and declaring the same variable multiple times in the same block is invalid.
Regarding the first question:
int x is both declaration and definition, whereas extern int x is only declaration.
This is why you get a redeclaration error.
Your first code, gets redeclaration error, because, in your case, x is having no linkage (local variable) and as per C11, chapter 6.7,
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,....
Your second code, compiles because the redeclaration is allowed, as both the statements reside in the global scope having external linkage.
Ref:
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

Double definition of variable [duplicate]

This question already has answers here:
About Tentative definition
(2 answers)
Closed 9 years ago.
As we know extern declaration of variables can be initialized.
#include<stdio.h>
extern int a=5; //will work as both definition and declaration.
int main()
{
}
Why this programme is compiling and running with no error.
extern int a=5; //will work as both definition and declaration.
int main()
{
}
int a; // isn't it second definition??
C has a concept of a "tentative definition". Most definitions without initializers are "tentative", so an arbitrary number of them are allowed, as long as they don't conflict with each other. At the end of the translation unit, the definition of the variable becomes basically the composite of those (e.g., if one definition says the variable is const and another says it's volatile, the variable will end up as both const and volatile.
A definition with an initializer is never tentative, so only one of them is allowed.

Resources