This answer confused me.
If we have two lines in same .c file:
extern int c;
int c;
How is the first line of code a declaration and second a definition?
Aren't both declarations?
How these two lines differ?
The extern keyword is what makes the first line a declaration. It say "this variable exists somewhere". A line like that can appear in a header file.
The second line is a definition because the extern keyword is not present. If you were to have this line in a header file, two source files that include that header will both define that variable and linking those two files will result in a variable redefinition error.
When the program you're writing consists of multiple source files linked together, where some of the variables defined, for example, in source file file1.c need to be referenced in other source files, so this is the reason why using extern.
About your question how these lines differ:
extern int c;
int c;
A variable is defined when the compiler allocates the storage for the
variable while
A variable is declared when the compiler is informed that a variable
exists (and this is its type); it does not allocate the storage for
the variable at that point.
so only int c; is defined while extern int c; is declared .
A definition creates space for a variable:
int c;
Wherever you put this line, either local, global, this says that a new variable c of type int shall come to life.
extern int c;
A declaration says that there is somewhere else some variable c of type int. By using extern, you say that c is defined somewhere else. If you put only an extern declaration without a definition somewhere else, you will have a link error. Using extern is the equivalent of a forward declaration of a function:
/* declaration */
int f(int x);
vs.
/* definition */
int f(int x) {
return x*x;
}
The first means that there is somewhere a function f returning an int and accepting an int as parameter. The latter is the actual function, its code, which also works both as a declaration and a definition.
IMO, this declaration-vs-definition naming is confusing. I hardly remember which one is what, and I usually need to think about it. You should, however, understand the what extern means and what a forward declaration is.
Long story short, defining something means providing all of the necessary information to create that thing in its entirety. However, declaring something means providing only enough information for the computer to know it exists.
Edit: To be clearer: A definition both defines and declares, a declaration ONLY declares. When you are using the extern keyword by definition you are not defining anything. Your confusion stems from the understanding of extern.
Related
I read from a book about tentative defination that,
A tentative definition is any external data declaration that has no
storage class specifier and no initializer. A tentative definition
becomes a full definition if the end of the translation unit is
reached and no definition has appeared with an initializer for the
identifier
Please explain what the above statement means.
Also, the difference between Declaration and Definition? I got mixed up due to this. :(
And why doesn't this program give an error:
#include <stdio.h>
int a; //Tentative definition
int a; //similarly this declaration too.
int main() //not getting any error with this code why its so?
{
printf("hi");
}
Also, what is wrong with this code:
#include<stdio.h>
printf("Hi");
int main(void){
return 0;
}
A variable declaration says, "there is a variable with the following name and type in the program".
A variable definition says, "Dear Mr. Compiler, please allocate memory for a variable with the following name and type now."
So there can be multiple declarations for the same variable, but there should be only one definition.
In C, pure declarations (that are not also definitions) are preceded with the keyword extern. So, since you do not have this keyword in your first example, what you have is two definitions. On its face, this would seem to be a problem (and is in fact an error in C++), but C has a special "tentative definition" rule which allows multiple definitions for the same variable in the same translation unit so long as they all match and at most one has an initializer. The C compiler, behind the scenes, combines all of the tentative definitions into a single definition.
Had you attempted to initialize both definitions, like this:
int a = 1;
int a = 2;
Then you would have had an error.
Your second question is more straightforward. In C, you simply cannot have executable statements outside of the body of a function. It's just not allowed. Think about it: when would you expect it to run if it were allowed?
The first works because both your definitions of a are tentative, which can be duplicated as often as you see fit. At the end of the translation unit, no non-tentative definition has been seen, so what you've specified for attributes is combined with defaults to give a final definition of a, so it'll have external linkage, static storage duration, and be initialized to 0.
The problem with the second has nothing to do with tentative definitions. Your printf("Hi"); needs to be inside a function to work -- it's not a declaration or a definition (tentative or otherwise); it's just not allowed there.
#include <stdio.h>
int main()
{
extern int a;
extern int a;
int a = 10;
return 0;
}
what is the problem with this code? Since multiple declaration is allowed in c what is the problem with this code
The problem with the code is that the compiler is first informed that a is a global variable (due to the extern keyword); and then a is defined as a local 'automatic' variable. Hence there is a conflict in the defined scope of a
As an alternative to automatic variables, it is possible to define variables that are external to all functions, that is, variables that can be accessed by name by any function. (This mechanism is rather like Fortran COMMON or Pascal variables declared in the outermost block.) Because external variables are globally accessible, they can be used instead of argument lists to communicate data between functions. Furthermore, because external variables remain in existence permanently, rather than appearing and disappearing as functions are called and exited, they retain their values even after the functions that set them have returned. —The C Programming Language
An external variable must be defined, exactly once, outside of any function; this sets aside storage for it. The variable must also be declared in each function that wants to access it; this states the type of the variable. The declaration may be an explicit extern statement or may be implicit from context. ... You should note that we are using the words definition and declaration carefully when we refer to external variables in this section. Definition refers to the place where the variable is created or assigned storage; declaration refers to places where the nature of the variable is stated but no storage is allocated. —The C Programming Language
From your question I observe that you are visualizing your program something like this
#include <stdio.h>
int main()
{
extern int a; //declaration
extern int a; //declaration
int a = 10; //declaration + definiton
return 0;
}
With above understanding of extern keyword. Your question is obvious.
Let us understand use extern of keyword thoroughly.
Extern variable declaration is a promise to the compiler that there would be a definition of a global variable some place else. Read This. In other words extern keyword tell the compiler that forget about this variable at the moment and left it to linker to link it with its definition. That is extern variables are actually linked to its definition by linker. Moreover Local variables have no linkage at all. So while searching for its definition compiler found a definition without linkage. Thats the error.
As a rule of thumb just remember when you declare any variable as extern inside any function then you can only define it outside of that function.(However there is no use of it).
Here I have two files externdemo1.c and externdemo2.c.In the first file,I have declared and initialized a character array arr at file scope.But I have declared it in the second file externdemo2.c without the extern keyword and made use of it there in the function display(). Here are my confusions arising from it.Please answer these three:
//File No.1--externdemo1.c
#include<stdio.h>
#include "externdemo2.c"
extern int display();
char arr[3]={'3','4','7'};
//extern char arr[3]={'3','4','7'};
//extern int main()
int main()
{
printf("%d",display());
}
//File No.2--externdemo2.c
char arr[3];
int display()
{
return sizeof(arr);
}
1) Why does the program compile fine even though I have declared arr without the extern keyword in externdemo2.c?I had read that the default linkage of functions is external,but I am not sure if that's so even for variables.I only know that global variables have extern storage class.
2) What is the rigorous difference between extern storage class and extern linkage.I badly need a clarification about this.In the first file,where I have defined the array arr,I haven't used the keyword extern, but I know that it has extern storage class by default.But in the second file, isn't there any default extern ,storage class or linkage,about the global variable arr,ie, in externdemo2.c?
3) Check the commented out line in the first file externdemo1.c.Just to test it, I had used the line extern char arr[3]={'3','4','7'};.But it gives the error 'arr' initialized and declared 'extern'.What does this error mean? I have also mentioned a commented line extern int main(),but it works fine without error or warning.So why can we use extern for a function even though a function is extern by default,but not for a variable,like arr here?
Please take some time to bail me out over this.It will clear most of my lingering doubts about the whole extern thing.It will be immense help if you can answer all 3 bits 1),2) and 3). Especially 3) is eating my brains out
Main questions
Basically, because you've included the source of externdemo2.c in the file externdemo1.c.
This is the big question. Because there is no initializer, the line char arr[3]; in externdemo2.c generates a tentative definition of the array arr. When the actual definition with initialization is encountered, the tentative definition is no longer tentative — but neither is it a duplicate definition.
Regarding extern storage class vs extern linkage...Linkage refers to whether a symbol can be seen from outside the source file in which it is defined. A symbol with extern linkage can be accessed by name by other source files in which it is appropriately declared. To the extent it is defined, extern storage class means 'stored outside of the scope of a function', so independent of any function. The variable defined with exern storage class might or might not have extern linkage.
Because it is not defined with the keyword static, the array arr has extern linkage; it is a global variable.
With the commented out line uncommented out, you have two definitions of one array, which is not allowed.
I observe that you must be compiling just externdemo1.c to create a program — the compiler is including the code from externdemo2.c because it is directly included. You can create an object file from externdemo2.c. However, you cannot create a program by linking the object files from both externdemo1.c and externdemo2.c because that would lead to multiple definitions of the function display().
Auxilliary questions
I have placed both files in the [same directory]. If I don't include the second file in the first, then when I compile the first file it gives the error undefined reference to display. Since I have used extern for that function in the first file, isn't the linker supposed to link to it even if I don't include the second file? Or the linker looks for it only in default folders?
There are a couple of confusions here. Let's try dealing with them one at a time.
Linking
The linker (usually launched by the compiler) will link the object files and libraries that are specified on its command line. If you want two object files, call them externdemo1.obj and externdemo2.obj, linked together, you must tell the linker (via the build system in the IDE) that it needs to process both object files — as well as any libraries that it doesn't pick up by default. (The Standard C library, plus the platform-specific extensions, are normally picked up automatically, unless you go out of your way to stop that happening.)
The linker is not obliged to spend any time looking for stray object files that might satisfy references; indeed, it is expected to link only those object files and libraries that it is told to link and not add others at its whim. There are some caveats about libraries (the linker might add some libraries not mentioned on the command line if one of the libraries it is told to link with has references built into it to other libraries), but the linker doesn't add extra object files to the mix.
C++ with template instantiation might be argued to be a bit different, but it is actually following much the same rules.
Source code
You should have a header, externdemo.h, that contains:
#ifndef EXTERNDEMO_H_INCLUDED
#define EXTERNDEMO_H_INCLUDED
extern int display(void);
extern char arr[3]; // Or extern char arr[]; -- but NOT extern char *arr;
#endif /* EXTERNDEMO_H_INCLUDED */
You should then modify the source files to include the header:
//File No.1--externdemo1.c
#include <stdio.h>
#include "externdemo.h"
char arr[3] = { '3', '4', '7' };
int main(void)
{
printf("%d\n", display());
return 0;
}
and:
//File No.2--externdemo2.c
#include "externdemo.h"
int display(void)
{
return sizeof(arr);
}
The only tricky issue here is 'does externdemo2.c really know the size of arr?' The answer is 'Yes' (at least using GCC 4.7.1 on Mac OS X 10.8.3). However, if the extern declaration in the header did not include the size (extern char arr[];), you would get compilation errors such as:
externdemo2.c: In function ‘display’:
externdemo2.c:7:18: error: invalid application of ‘sizeof’ to incomplete type ‘char[]’
externdemo2.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]
Your program looks a bit err. To me the #include "externdemo2.c" line appears invalid.
Following is the correction I have made and it works.
//File No.1--externdemo1.c
#include <stdio.h>
extern char arr[3];
extern int display();
int main()
{
printf("%d", arr[0]);
printf("%d",display());
}
//File No.2--externdemo2.c
char arr[3]={'3','4','7'};
int display()
{
return sizeof(arr);
}
Please follow the below links for better understanding:
Effects of the extern keyword on C functions
How do I use extern to share variables between source files?
Using #include as shown will make both as one file only. You can check the intermediate file with flag -E, as in:
gcc -E externdemo1.c
I have the following source code which interests me.
#include <stdio.h>
extern int foo;
int foo = 32;
int main()
{
printf("%d", foo);
}
This a perfectly normal piece of code, and when I compile it with
gcc -Wall -Wextra -pedantic foo.c
I get no warnings.
And it seems weird, because a variable is defined both as external, and also global in the same file.
I'm quite sure that it's easy to the linker to find the reference for the external variable in the same file, but doesn't it look like a coding error? And if so, why doesn't the compiler warn about this?
There's nothing weird. You first made a declaration of a variable (you promised the compiler that it exist) and then you actually defined it. There's no problem in that.
Also, by default, all variables that aren't local to functions and aren't defined as static are extern.
You seem to misunderstand what extern does. extern simply makes your declaration just a declaration instead of a definition.
int i; //definition of i
extern int i; //declaration of i
It is perfectly normal to have multiple declarations of the same variable, but only one definition should be present in the whole program. Compare this with a function
void f(void); //declaration
void f(void) //definition(and redeclaration)
{
} //definition
In order to use a variable or function, you only need its declaration. Its definition may appear anywhere in the program (the linker will find it). Anywhere can be the same file, another file, or even an external library.
And it's seems weired, because a variable is defined both as external, and also global in the same file.
extern int foo;
says: it declares without defining an object of type int named foo.
int foo = 32;
it declares and defines an object of type int named foo with external linkage.
There is no contradiction and it is valid C code.
The difference is that the former is a declaration -> extern declares a variable and says it will be available somewhere around. You can have as many declarations as you want and the latter is a definition which must be there exactly once.
So there should be no warning and no error.
extern is a way to provide visibility to a variable that is defined elsewhere...
extern is like a promise...
in example.h
extern int g;// promises that this will be in the object code to anything that includes example.h
example. c
int g;
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!