This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Redefinition allowed in C but not in C++?
#include<stdio.h>
int i;
int i;
int main()
{
// int i;
// int i;
printf("%d\n",i);
return 0;
}
~
The above code runs wihtout giving any error gcc -Wall -Werror demo.c -o demo
But when I uncomment the local i variables the comment out the global i ,It gives me errors .
In function ‘main’:
demo.c:7:6: error: redeclaration of ‘i’ with no linkage
demo.c:6:6: note: previous declaration of ‘i’ was here
What is this local global concept here ?, Anybody Please explain.
In C99 (see more specifically section 6.2), global declarations have by default external linkage (6.2.2§5). In that case (6.2.2§2), both declarations of i refer to the same object. On the contrary, local variables have no linkage (6.2.2§6), and are thus supposed to refer to unique identifiers (again 6.2.2§2): you would thus end up with two local variables of the same name in the same scope, which is not allowed (6.2.1§5: Different entities designated by the same identifier either have different scopes, or are in different name spaces)
You can have more than one definition of your variable in a global scope, if all definitions agree (all have the same type) and the variable is initialized in not more than one place.
J.5.11 Multiple external definitions
There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).
Related
This question already has answers here:
Why does initializing an extern variable inside a function give an error?
(5 answers)
Closed 6 years ago.
extern int a = 10; // it is not giving error
int main ()
{
extern int b = 10; //it is giving error
return 0;
}
error: ‘b’ has both ‘extern’ and initializer
extern int b = 10;
Referring to C11 (N1570) 6.7.9/5 Initialization:
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.
The rule is placed within constraints section, so any conforming compiler should reject the code, that violates it.
The point of extern keyword at the block scope is to declare some existing object from outside scope. It would not make much sense to declare an object and give it some other value at the point of declaration.
The recommended way of declaring external objects is to put their declarations at the file scope (at the top of source code), thus they are easy to spot and manage by maintenance programmer.
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.
I thought externs were to share variables between compilation units. Why does the below code work ? and how does it work exactly ? Is this good practice ?
#include <stdio.h>
int x = 50;
int main(void){
int x = 10;
printf("Value of local x is %d\n", x);
{
extern int x;
printf("Value of global x is %d\n", x);
}
return 0;
}
Prints out :
Value of local x is 10
Value of global x is 50
When you use the extern keyword, the linker finds a symbol with a matching name in object files / libraries / archives. Symbols are, simply speaking, functions and global variables (local variables are just some space on the stack), thus the linker can do it's magic here.
About it being a good practice - global variables in general are not considered a good practice since they cause spaghetti code and 'pollute' the symbols pool.
You might (or might not) be interested to know that GCC (4.9.1) and clang (Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)) have divergent views on the acceptability of the following code, which is a minor adaptation of the code in the question:
#include <stdio.h>
static int x = 50; // static instead of no storage class specifier
int main(void)
{
int x = 10;
printf("Value of local x is %d\n", x);
{
extern int x;
printf("Value of global x is %d\n", x);
}
return 0;
}
I called the source file ext.c.
$ clang -O3 -g -std=c11 -Wall -Wextra -Werror ext.c -o ext
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror ext.c -o ext
ext.c: In function ‘main’:
ext.c:9:20: error: variable previously declared ‘static’ redeclared ‘extern’
extern int x;
^
ext.c: At top level:
ext.c:2:12: error: ‘x’ defined but not used [-Werror=unused-variable]
static int x = 50;
^
cc1: all warnings being treated as errors
$
The problem is to determine which compiler is correct because they can't both be right unless the program is exhibiting undefined behaviour — which, if you bother to read to the end, will turn out to be the case.
The relevant section of the C11 standard is:
6.2.2 Linkages of identifiers
¶1 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.29) There are
three kinds of linkage: external, internal, and none.
¶2 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.
¶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.30)
This means that the first or outermost declaration (definition) of x in the code above 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,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.
This paragraph needs detailed deconstruction below.
¶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.
In the original code in the question, the second sentence says that the first declaration (definition) of x has external linkage.
¶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.
The x declared (defined) at the start of the function is 'a block scope identifier …' and therefore has no linkage.
¶7 If, within a translation unit, the same identifier appears with both internal and external
linkage, the behavior is undefined.
29) There is no linkage between different identifiers.
30) A function declaration can contain the storage-class specifier static only if it is at file scope; see
6.7.1.
31) As specified in 6.2.1, the later declaration might hide the prior declaration.
Dissecting paragraph 4
Paragraph 4 is the key one here. Restating it and annotating it:
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)
The third or innermost declaration of x is declared in a scope in which a prior declaration of that identifier is visible — the int x = 10; declaration is visible (the static int x = 50; declaration is invisible, having been shadowed by the visible declaration). The footnote refers to §6.2.1 Scopes of identifiers but I don't think ithat says anything surprising (however, I'll quote the relevant paragraphs — ¶2 and ¶4 — if you think that's necessary).
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.
This does not apply; the prior declaration specifies neither internal nor external linkage.
If no prior declaration is visible, or if the prior declaration specifies no linkage,
There is a prior declaration that's visible, and that declaration specifies no linkage.
then the identifier has external linkage.
So, the innermost x has external linkage, the outermost x has internal linkage, and as a consequence, paragraph 7 says the resulting behaviour is undefined. That means that both compilers are correct; if the behaviour is undefined, any behaviour is correct — and different compilers are allowed to have divergent views on what is correct, and GCC and clang exhibit divergent views. On the whole, GCC's "it is a problem that should be reported" view is safer for the programmer.
In the original code, the outermost x has external linkage, the innermost x also has external linkage, and as a consequence paragraph 7 does not apply, and the innermost declaration of x refers to the outermost declaration (and definition) of x.
Apart from showing that interpreting the standard is hard work, this whole answer (diatribe) also shows that using multiple compilers (if possible on different platforms) is a good idea. It gives you the maximum chance of finding problems. Depending on a single compiler leaves you vulnerable to missing problems that another compiler might spot.
This question already has answers here:
Use of 'extern' keyword while defining the variable
(2 answers)
Closed 8 years ago.
I was trying out programs based on extern and as I understand, this is helpful when accessing variables across multiple files having only one definition.
But I tried a simple program as below without extern and thing seem to work when I expected it would fail during linking process
file5.c:
#include <stdio.h>
#include "var.h"
int a = 20;
int main() {
printf("\n File5.c a = %d", a);
test();
return 0;
}
file6.c:
#include <stdio.h>
#include "var.h"
int test() {
printf("\n File6.c a = %d",a);
}
var.h
int a;
As I have included var.h in all header files without extern, int a would be included in both the .c file and during linking, compiler should have thrown a warning or error message but it compiles file without any issue.
Shouldn't var.h have the following extern int a?
It is generally best if the header uses extern int a;. See also How do I share a variable between source files in C?
The standard says:
ISO/IEC 9899:2011 §6.9.2 External object definitions
Semantics
¶1 If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
¶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. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.
Thus, what's in the header is a tentative definition of the variable. At the end of the translation unit (TU) for file5.c, you have no longer got a tentative definition; the 'external definition' specified by int a = 20; has specified that. At the end of the TU for file6.c, you have a definition equivalent to int a = 0;.
When you try to link file5.c and file6.c, you should run into multiple definitions of a. However, there is a common extension, documented in the standard in Annex J:
J.5.11 Multiple external definitions
¶1 There may be more than one external definition for the identifier of an object, with or
without the explicit use of the keyword extern; if the definitions disagree, or more than
one is initialized, the behavior is undefined (6.9.2).
Your compiler is providing the extension identified by §J.5.11, and therefore (legitimately) not complaining.
580
I am trying a small example to know about the static external variable and its uses. The static variable is of local scope and the external variable is of global scope.
static5.c
#include<stdio.h>
#include "static5.h"
static int m = 25;
int main(){
func(10);
return 0;
}
static5.h
#include<stdio.h>
int func(val){
extern int m;
m = m + val;
printf("\n value is : %d \n",m);
}
gcc static5.c static5.h
o/p :
static5.c:3: error: static declaration of m follows non-static declaration
static5.h:3: note: previous declaration of m was here
EDITED
The correct program :
a.c:
#include<stdio.h>
#include "a1_1.h"
int main(){
func(20);
return 0;
}
a1.h:
static int i = 20;
a1_1.h:
#include "a1.h"
int func(val){
extern int i;
i = i + val;
printf("\n i : %d \n",i);
}
This works fine perfectly fine. But this is compiled into a single compilation unit. Hence could able to access the static variable . Across the compilation unit we cannot use the static variable by using the extern variable.
static has a very simple logic to it. If a variable is static, it means that it is a global variable, but it's scope is limited to where it is defined (i.e. only visible there). For example:
Outside a function: global variable but visible only within the file (actually, the compilation unit)
Inside a function: global variable but visible only within the function
(C++) Inside a class: global variable but visible only to the class
Now let's see what the C11 standard says regarding static and extern (emphasis mine):
6.2.2.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.
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.
6.2.2.7
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
So the standard says that first, if you have:
static int m;
extern int m;
then the second declaration (with extern) would regard the first one and in the end m would still be static.
However, in any other case, if there are declarations with both internal and external linkage, the behavior is undefined. This actually leaves us with only one option:
extern int m;
static int m;
i.e., extern declaration before static declaration. gcc was nice enough to give you error in this case of undefined behavior.
Remember this (quoting Eli Bendersky):
A static variable inside a function keeps its value between
invocations.
A static global variable or a function is "seen" only in
the file it's declared in
In your code, static int m = 25; means that m's scope is limited only to that file, that is, it is only visible inside static5.c and nowhere else.
If you would like to make use of m outside of static5.c make sure to remove the keyword static from the declaration of the variable.
For a more canonical explanation, along with an example, see this answer by Eli Bendersky
EDIT: (according to Klas' recommendation) **The actual scope is a compilation unit, not the source file. The compilation unit is the way the file looks after the preprocessor step
The problem is exactly as stated in the error message. m is declared a normal int but is later defined as a static int.
extern tells the compiler/linker to look for the variable in the global table of variables.
static (outside a functon) tells the compiler to exclude the variable from the global table of variables.
Do you see the conflict?
To fix the problem, either remove the static keyword from the definition or move the definition above the inclusion of static5.h.
It should be noted that the way you have designed your files is not considered best practice. Include files don't usually contain functions.
remove the keyword static while declaring m and the errors will be removed and you will be able to get the answer as 50. The static keyword makes the scope to restrict within the file.