Extern declaration follows non-extern declaration in same scope - c

#include <stdio.h>
extern int x;
int main()
{
int x;
x = 1;
printf("%d", x);
}
#include <stdio.h>
int main()
{
extern int x;
int x;
x = 1;
printf("%d", x);
}
I am learning about extern keyword and I was told that the word extern is used to declare variable and compiler will not allocate for this variable.
But when I write 2 codes, the first code run normally and the second has an error.
Please help me explain why it has this difference. Thanks.

Conflicting Declarations in Same Scope
When extern int x; appears outside a function, it declares x at file scope. Then, when int x; appears inside the function, it declares a new instance of x that is unrelated to the earlier extern int x;. This is allowed by the C language, so the compiler does not complain about it.
When extern int x; appears inside the function, it declares x at block scope. Then, when int x; appears after it, it attempts to declare a different x in the same scope. This is not allowed by the C standard, so the compiler reports an error.
The extern keyword is not particularly relevant here—the error is caused by the fact that there are two conflicting declarations of the same identifier. For example:
char c;
int main(void)
{
char d;
int c; // Allowed, new declaration in new scope.
int d; // Not allowed, conflicting declaration in same scope.
}
Rules About Declarations
The rules about C declarations have some irregularities due to the history of C development. Consider these declarations at file scope:
extern int x;
int x;
The first declaration does (or does not do) several things:
It says x is an identifier for an int.
It says x has external linkage, meaning it can be made (during linking of the object modules) to refer to an object named x declared somewhere else.
It does not define an int.
For the second declaration:
It says x is an identifier for an int.
It says x has external linkage (because external is the default for declarations for objects without a storage class specifier like static outside functions).
It defines an int. (It is actually a tentative definition, but we will not deal with that here.)
Both of these declarations say x is an identifier for an int and has external linkage. The difference between them is the first does not define an object (it merely says x is a name for an object defined somewhere else) and the second does define an int (so it is the somewhere else). So these declarations do not conflict and are allowed.
On other hand, consider these same declarations inside a function. Then they are at block scope.
Then extern int x; has the same meaning as above: x is an identifier with external linkage for an object defined elsewhere.
But int x; has a different meaning. Instead of saying x has external (or internal) linkage, it says x has no linkage, because no linkage is the default for declarations in block scope. This creates a conflict because C 2018 6.7 3 says an identifier with no linkage shall not be declared more than once in the same scope (and name space, not addressed here) except for typedef names and tags with certain conditions.
Scopes
C has four kinds of scopes:
File scope is for declarations outside of functions and lasts to the end of the source file being compiled.
Block scope is for declarations inside functions and lasts until the end of a block (discussed below).
Function prototype scope is for declarations in the parameters of function prototypes. (For example, in void foo(int n, float a[n][n]);, n and a have function prototype scope.)
Function scope is for labels to be used in goto statements.
A compound statement is a list of declarations and statements inside { and }. Each compound statement is a block, which creates a new scope for declarations. The main body of a function is a compound statement that is a block, and it may have additional compound statements inside it, each starting a new scope.
Blocks are also created by switch, if, do, while, and for statements, but they are largely unimportant for the first four of those, as only the for statement provides an opportunity for further declarations. For example, in a for statement, you can write for (int x = 3; x < 20; ++x), and that creates a new instance of x because the for statement starts a new block.

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.

understanding of extern storage class [duplicate]

This question already has answers here:
What is the difference between a definition and a declaration?
(27 answers)
Closed 5 years ago.
Can you please someone explain me the flow of below problem,
#include <stdio.h>
int main(){
extern int a;
printf("%d\n",a);
return 0;
}
int a = 20;
and the output is 20. I am not sure where is the variable a getting defined and where is it getting declared?
The variable a is declared and defined as a global variable in the line:
int a = 20;
The extern line just tells the main() function scope that a is defined in another place.
In this case, the use of extern is not really necessary. You could just declare and define a before the main() function, and then main() would be familiar with it.
Usually, you would use extern when you want to use a variable or a function that was defined in another source file (and not just later in the same source file).
The C programming language has been designed to be one-pass, so that the compiler could process each line only once from top to bottom. So considering your program:
#include <stdio.h>
int main(){
extern int a;
printf("%d\n",a);
return 0;
}
int a = 20;
The identifier a is declared twice, and defined once.
Before the 4th line extern int a;, the compiler doesn't know anything about the identifier a. The declaration extern int a; has the block scope within the function main, and it declares the identifier a as an int and that its storage duration is static and linkage is external. So the compiler can write code that access a global identifier by name a as an int variable that could be defined in another module (external linkage). This is what the compiler does on line 5 when it is used in printf.
Finally at line 9, int a = 20; is another declaration and definition. This declares and defines a as a int with static storage duration, and external linkage.
If you'd put the int a = 20; before the main, the declaration extern int a; would be useless, because it doesn't add anything. I tend to put my main and other depending functions last in my source code, so that minimal amount of extra declarations are needed.
extern is syntactically a "storage class" keyword. But there is no such storage class. C has "static storage", "dynamic storage (malloc, etc) and "automatic storage" (local variables, usually represented using a stack).
If an identifier is declared extern inside a block scope, it means that the declaration refers to an external definition. If the entity being declared is an object, then it has static storage, simply because external objects have static storage. It can be a function too; functions aren't said to have storage.
In C, there is a concept called "linkage". Objects declared outside of any function at file scope, and functions, can have "external" or "internal" linkage.
If we have extern in a block scope, as you have in the example program, there can be a prior declaration of the same name at file scope, or in a nested scope, like this:
static int x;
/* ... */
{
extern int x;
}
Here, the inner x refers to the outer x, and, in spite of being "extern", it has internal linkage because of the "static".
In a nutshell, extern usually means "refer to the earlier declaration, and if there isn't one, declare this as an identifier with external linkage".
The word "external" refers to two separate concepts: the aforementioned "external linkage" and also to the meaning "outside of any function", as in "external declaration". Confusingly, "external declarations", like the static int x above, can have "internal linkage"!
In your program, things are correct because the block scope extern declaration of a and the later int a = 20, which are in separate scopes, happen to independently agree with each other.
The int a = 20; is an external declaration, which is also an external definition (because of the initializer). Since in that scope, no prior declaration of a is visible, it gets external linkage.
So, where is a defined? It is defined as an object with external linkage, in the entire translation unit as a whole. That translation unit is what defines a. a is declared in every place of the program where a declaration appears; and its definition is also a declaration. It is declared in main and also in the last line of the translation unit's source code.
A "declaration" is syntax which makes a name known in some scope. It's a concept that is active during the translation of a program. A "definition" is the fact that some object or function is provided in some translation unit. Translated units still provide definitions, but need not retain information about declarations. (Which is why when we make libraries, we provide header files with declarations in them!)
From the point of view of your main function, that function doesn't "care" where a is defined. It has declared a in such a way that if a is used, then an external definition of a, with external linkage, must exist. That definition could come from anywhere: it could be in the same translation unit, or in another translation unit.
When ever you declare a variable as extern then It means that Variable is declared as global and you cannot initialize the variable there.Because no memory is allocated for that variable It is just declared as a Variable
you can define it some where in your code.
Let us take an example ..consider the code
int main()
{
extern int i;
i=10;
printf("%d",sizeof(i));
}
here you get an error that int 'i' is not defined
therefore you need to write it as:
int main()
{
extern int i;
int i=10;
printf("%d",sizeof(i));
}
In case of your code:
This is declaration
extern int a;
This is definition:
int a = 20;
The storage class extern specifies storage duration and linkage of the object the identifier refers to:
The storage duration is set to static, which means the variable is alive for the whole time the program runs. As you declare that variable inside a function scope, this matters in your example, because in function scope, the default storage duration would be automatic.
The linkage is set to external, this just means different translation units of the same program can share the object. It has the side effect that a definition in another (file) scope is acceptable, as shown in your example. This is a logical consequence of the shared nature, you would typically declare a variable with external linkage in all translation units using it, but define it only in one.

Why re-declaration of global variables is valid but not local of local variables? [duplicate]

In the following code, why do multiple declarations (and one definition) work fine for a global variable x but not for a local variable y which is inside the main() function? It shows the following 2 errors:
1) redeclaration of 'y' with no linkage
2) previous declaration of 'y' was here
Why is it showing error for the local variable but not global variable? Not only my book, but the following 2 links from this forum clearly state that we can declare a variable multiple times (though define only once).
link1
link2
And kindly take care to explain what does the "with no linkage" part of the first error "redeclaration of 'y' with no linkage" mean? What linkage and to whom? Where would a local variable be linked?
#include<stdio.h>
int x;
int x;
int x=303;
int main(void)
{
int y;
int y;
int y=776; //Works fine if above 2 declarations are removed!!
printf("The value of x is %d,and of y is %d",x,y);
}
In C and C++, int y; within a function is both a declaration and a definition.
In C, int x; in the file scope (outside any function) is a declaration and a tentative defintion. Multiple tentative definitions are allowed; only one definition is allowed.
This is the way defined in the C99 standard, section 6.2.2, part 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.
The "global" variables x have external linkage, so they denote the same object. The local y variables, on the other hand, has no linkage, so there is a collision.
References: C99 Standard.
With external variables, any declaration that isn't an initialisation is a tentative definition. These by themselves don't create any storage, so multiple ones are allowed. So taking your example:
int x; // tentative def
int x; // and again -- ok
int x=303; // definition -- ok
int x=303; // multiple definition -- error
If at the end of the file there have been only tentative definitions, the variable is defined once, and set to 0.
This means that if you link to another file which also has a tentative definition of x, you'll have an error according to the standard. Most compilers/linkers have always allowed this, though, and it's defined in the standard as an extension.
With local variables, each declaration is a definition because of scope rules. This, however, is allowed:
void func(void)
{
int y = 0;
{
int y = 1; // a completely different y
}
}

In C,why is multiple declarations working fine for a global variable but not for a local variable?

In the following code, why do multiple declarations (and one definition) work fine for a global variable x but not for a local variable y which is inside the main() function? It shows the following 2 errors:
1) redeclaration of 'y' with no linkage
2) previous declaration of 'y' was here
Why is it showing error for the local variable but not global variable? Not only my book, but the following 2 links from this forum clearly state that we can declare a variable multiple times (though define only once).
link1
link2
And kindly take care to explain what does the "with no linkage" part of the first error "redeclaration of 'y' with no linkage" mean? What linkage and to whom? Where would a local variable be linked?
#include<stdio.h>
int x;
int x;
int x=303;
int main(void)
{
int y;
int y;
int y=776; //Works fine if above 2 declarations are removed!!
printf("The value of x is %d,and of y is %d",x,y);
}
In C and C++, int y; within a function is both a declaration and a definition.
In C, int x; in the file scope (outside any function) is a declaration and a tentative defintion. Multiple tentative definitions are allowed; only one definition is allowed.
This is the way defined in the C99 standard, section 6.2.2, part 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.
The "global" variables x have external linkage, so they denote the same object. The local y variables, on the other hand, has no linkage, so there is a collision.
References: C99 Standard.
With external variables, any declaration that isn't an initialisation is a tentative definition. These by themselves don't create any storage, so multiple ones are allowed. So taking your example:
int x; // tentative def
int x; // and again -- ok
int x=303; // definition -- ok
int x=303; // multiple definition -- error
If at the end of the file there have been only tentative definitions, the variable is defined once, and set to 0.
This means that if you link to another file which also has a tentative definition of x, you'll have an error according to the standard. Most compilers/linkers have always allowed this, though, and it's defined in the standard as an extension.
With local variables, each declaration is a definition because of scope rules. This, however, is allowed:
void func(void)
{
int y = 0;
{
int y = 1; // a completely different y
}
}

Confusion between declaration and definition of a variable in C

I am new to C and I experience some confusion between the declaration and definition of a variable. Another thing I would like to know is if the following is true:
"Declaration appears many times and definition comes once."
Also:
int x;
Is this a declaration only? Since memory is allocated for x then why isn't this a definition instead of a declaration?
Simply writing int x; at either global scope or local scope, is both a declaration and definition. Typically, the declaration tells the compiler "This variable will exist, at some point, under this name, so you can use it." The definition tells the compiler to actually arrange for the variable to be created - obviously this can only happen once.
Typically the way you'll use this is by putting in a header file:
// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined
extern int bar; // Declare a variable bar
#endif
And in a single source file
#include "foo.h"
int bar; // Define bar
If you were to define bar in multiple files, you would get an error; you can't create the variable twice. But you do have to tell the compiler about it in every source file you use bar in. Hence the extern declaration.
The precise semantics are defined in §6.9.2 of the C standard and can be summarized as follows:
When a variable is declared at file scope with an initializer, it is an external definition. (§6.9.2/1)
When a variable is declared at file scope without an initializer, and without a storage-class specifier or with the static storage-class specifier, it is a tentative definition. If the translation unit (file) has one or more tentative definitions and no external definition, the compiler automatically adds a true file scope declaration at the end of the translation unit, with a zero initializer. (§6.9.2/2)
What this means is that, strictly speaking, int x; is not a definition; but it automatically creates a definition if and only if there is no other definition with an initializer, and no static definition (this third case is undefined behavior due to linkage disagreement per §6.2.2/7)
Note that extern int x; is not an external definition. It is a declaration with an extern storage class specifier. As such, extern int x; alone does not cause a definition to be created, but if you have both:
extern int x;
int x;
Then you will end up having a definition created at some point in the file.
It is also, technically speaking, legal to do this:
extern int x;
int x;
int x = 42;
In this case, the int x; in the middle is superfluous and has no effect. That said, this is poor form, as it's confusing in this case where the actual definition is.
This isn't something you see too much in C, but it works like this:
In a header file, you can have a line like this:
extern int x; //declaration
Because of the extern modifier, this tells the compiler that there is an int named x somewhere. The compiler doesn't allocate space for it - it just adds int x to the list of variables you can use. It'll only allocate space for x when it sees a line like this:
int x; //definition
You can see that because only the int x; line changes your executable, you can have as many extern int x; lines as you feel like. As long as there's only int x; line, everything will work like you want it to - having multiple declarations doesn't change a thing.
A better example comes from C++ (sorry if this is a C-only question - this applies to structs as well, but I don't know the syntax off the top of my head):
class Pineapple; //declaration
Pineapple* ptr; //this works
Pineapple pine; //this DOES NOT work
This declaration tells the compiler that there's a class called "Pineapple". It doesn't tell us anything about the class (how big it is, what its members are). We can use pointers to Pineapples now, but we can't yet have instances - we don't know what makes up a Pineapple, so we don't know how much space an instance takes up.
class Pineapple
{
public:
int ounces;
char* name;
}; //definition
Pineapple* ptr; //still works
Pineapple pine; //this works now too!
//we can even get at member variables, 'cause we know what they are now:
pine.ounces = 17;
After a definition, we know everything about the class, so we can have instances, too. And like the C example, you can have multiple declarations, but only one definition.
Hope this helps!

Resources