understanding extern keyword in C - c

What does this statement extern int x=4; mean in C? Is it similar to int x=4;?
when i am compiling the code extern int x=4; outside a block(function) ,the compiler raises a warning, not error.
Warning:-
warning: 'x' initialized and declared 'extern'
extern int x=3;
Meanwhile when i am compiling the code extern int x=4;inside a block(function), the compiler raises an error .
Error:-
error: 'x' has both 'extern' and initializer
extern int x=3;
What's going on , i am not getting.What does the statement extern int x=4; mean actually? Please clear the concept.
Thanks in Advance...

The meaning of extern is a bit complicated because C was developed over time by different people trying different things, rather than being designed from the start with knowledge of what the end product should be.
The reason extern int x=4; inside a block is an error is it violates this rule in C 2018 6.7.9 5:
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.
I am not sure what the exact motivation for that rule is. One motivation might be, “The compiler is busy defining a function here, and defining another thing at the same time is unexpected, awkward, or difficult for the compiler.” I am not sure it would actually be difficult to implement, but maybe it could be a problem for some compilers, especially early compilers way back when.
A reason for the warning is that we usually use extern with declarations to say “We are only declaring this identifier to tell you about an object defined somewhere else.” That is a matter of common practice, not a rule.1 But the initialization says “We are defining an object here.” So that is a contrast, and the compiler warns you about it. However, it is not an actual rule violation, so the compiler does not report it as an error.
Footnote
1 There are rules that fit this practice. At file scope, int x; is a tentative definition, whereas extern int x; is a declaration that is not a definition. So that comports with the practice; extern int x; says we are just declaring x, whereas int x; says we might be defining it. However, int x = 4; and extern int x = 4; are both definitions and do not violate any rule.

Intuitively, I like to think of extern as "reference a (global) object in another file." You can't define a global object inside a function, so that concept makes no sense.
The initialization of an extern variable is possible, but not recommended. If the instantiation is not initialized, and you're conditionally adding one of a set of files that initializes the variable, and multiple that use it. That's probably a bad idea, but if you're blocking off a special part of memory in the declaration, I could see a use case for it. Another use case is if it COULD be a global variable in another file, but you may or may not be including that file. In the case there is no external declaration, the compiler will allocate memory for you and treat it like a regular global variable.
If you initialize multiple values in multiple files, you'll almost certainly get a linker error.

Related

Initialization of extern variable warning in GCC (C18)

The question is not "why can't I initialize a variable declared as extern", because it's something completely possible with file scope variables (not with block scope variables). The thing is that GCC yields a warning (with -Wall switch) in this particular case:
extern int n = 10; // file scope declaration
GCC yields:
test.c:5:12: warning: ‘n’ initialized and declared ‘extern’
The code works perfectly, though.
Furthermore, note that the following definition is absolutely equivalent to the first one:
int n = 10; // file scope declaration
In both cases, the variable has the same linkage and storage type. The thing is that, being both absolutely equivalent, the second version doesn't yield any warning in GCC (with -Wall).
Why is that?
My guess is that you usually use extern to explicitly set a reminder about the fact that this is a declaration that refers to an external object defined elsewhere, so that you shouldn't (though you could) initialize the variable (bear in mind that the standard doesn't let you define a variable twice inside the same linkage, in this case, external).
So, is that a right guess, or perhaps there's more to it, which I'm not able to see?
A compiler can warn about anything it likes to. If it is attentive, it warns about things it considers as "suspicious".
So it does here.
My personal opinion about the reasoning agrees to yours:
My guess is that you usually use extern to explicitly set a reminder about the fact that this is a declaration that refers to an external object defined elsewhere so that you shouldn't (though you could) initialize the variable (bear in mind that the standard doesn't let you define a variable twice inside the same linkage, in this case, external).
That GCC finds it suspicious to initialize an explicit extern declared variable because it is usually more common to define the variable in one file and then in another file, which can depend on the context, cause an error at linking and indeed can be the reason but our assumptions aren't worth much.
The question for the actual "why" you need to ask the implementors of GCC itself.
The keyword extern is used to declare a variable but not define it (similar to function declarations). It is typically used in header files to export a variable from a module. However, it is often better to introduce a function which returns its value.
Example:
M.h
extern int M_n;
M.c
int M_n = 10;

Is extern keyword in C redundant?

I have found that I could achieve the desired results without using extern (though I do agree that it gives reader some kind of an hint about the variable). In some cases using extern gave undesired results.
xyz.h
int i;
file1.c
#include "xyz.h"
....
i=10;
....
file2.c
#include "xyz.h"
main()
{
printf("i=%d\n",i);
}
Of course, it was a large project, broke it down for simple understanding. With extern keyword, I couldnt get desired results. In fact, I got linker error for the variable i with "extern" approach.
Code with "extern" approach,
file1.c
int i;
main()
{
i=10;
}
file2.c
extern int i;
foo()
{
printf("i=%d\n",i);
}
This gave linker error. I just wanted to know why it worked in the first case and also the practical case where we cannot do it without using the keyword "extern". Thanks.
Formally, your first program is invalid. Defining a variable in header file and then including this header file into multiple translation units will ultimately result in multiple definitions of the same entity with external linkage. This is a constraint violation in C.
6.9 External definitions
5 An external definition is an external declaration that is also a
definition of a function (other than an inline definition) or an
object. If an identifier declared with external linkage is used in an
expression (other than as part of the operand of a sizeof operator
whose result is an integer constant), somewhere in the entire program
there shall be exactly one external definition for the identifier;
otherwise, there shall be no more than one.
The definition of i in your first example is a tentative definition (as it has been mentioned in the comments), but it turns into a regular full fledged external definition of i at the end of each translation unit that includes the header file. So, the "tentativeness" of that definition does not change anything from the "whole program" point of view. It is not really germane to the matter at hand (aside for a little remark below).
What makes your first example to compile without error is a popular compiler extension, which is even mentioned as such in the language standard.
J.5 Common extensions
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).
(It is quite possible that what originally led to that compiler extension in C is some implementational peculiarities of tentative definition support, but at abstract language level tentative definitions have nothing to do with this.)
Your second program is valid with regard to i (BTW, implicit int is no longer supported in C). I don't see how you could get any linker errors from it.
There are at least 2 cases where extern is meaningful and not "redundant":
For objects (not functions) at file scope, it declares the object with external linkage without providing a tentative definition; tentative definitions turn into full definitions at the end of a translation unit, and having the same identifier defined with external linkage in multiple translation units is not permitted.
At block scope (in a function), extern allows you to declare and access an object or function with external linkage without bringing the identifier into file scope (so it's not visible outside the block with the declaration). This is useful if the name could conflict with something else at file scope. For example:
static int a;
int foo(void)
{
return a;
}
int bar(void)
{
extern int a;
return a;
}
Without the extern keyword in bar, int a; would yield a local variable (automatic storage).

if global variable have default external linkage then why can't we access it directly in another file?

I have gone through following questions:
Global variable in C are static or not?
Are the global variables extern by default or it is equivalent to declaring variable with extern in global?
Above links describe that if we define global variable in one file and haven't specified extern keyword they will be accessible in another source file because of translation unit.
Now I have file1.c in that have defined following global variable and function:
int testVariable;
void testFunction()
{
printf ("Value of testVariable %d \n", testVariable);
}
In file2.c have following code
void main()
{
testVariable = 40;
testFunction();
}
Now I am getting error: 'testVariable' undeclared (first use in this function) -- why?
Note: both files are used in same program using makefile.
As per my understanding both function and global variable have default external linkage. So function we can use directly by it's name in another file but variable can't why?
Can any one have idea?
EDIT:
From the below answer i get idea that like in case of function old compiler will guess and add an implicit declaration but in case of variable it can't. Also C99 removed implicit declaration but still I am getting warning in C99 mode like:
warning: implicit declaration of function ‘testFunction’.
Now have gone through below link:
implicit int and implicit declaration of functions with gcc compiler
It said that compiler take it as diagnostic purpose and not give error. So compiler can process forward.
But why in case of variable it can't process further? Even in case of function if compiler proceed and if actual definition not there then at linking time it will fail. So what's benefit to move forward??
There are two things in play here: The first is that there is a difference between a definition and a declaration. The other thing is the concept of translation units.
A definition is what defines the variable, it's the actual place the variable exists, where the compiler reserves space for the variable.
A declaration is needed for the compiler to know that a symbol exists somewhere in the program. Without a declaration the compiler will not know that a symbol exists.
A translation unit is basically and very simplified the source file plus all its included header files. An object file is a single translation unit, and the linker takes all translation units to create the final program.
Now, a program can only have a single definition, for example a global variable may only exist in a single translation unit, or you will get multiple definition errors when linking. A declaration on the other hand can exist in any number of translation units, the compiler will use it to tell the linker that the translation references a definition in another (unknown at time of compilation) translation unit.
So what happens here is that you have a definition and a declaration in file1.c. This source file is used as input for one translation unit and the compiler generates a single object file for it, say file1.o. In the other source file, file2.c, there is no definition nor any declaration of the global variable testVariable, so the compiler doesn't know it exists and will give you an error for it. You need to declare it, for example by doing
extern int testVariable; // This is a declaration of the variable
It's a little more complicated for the function, because in older versions of the C standard one didn't have to declare functions being used, the compiler would guess and add an implicit declaration. If the definition and the implicit declaration doesn't match it will lead to undefined behavior, which is why implicit function declarations was removed in the C99 standard. So you should really declare the function too:
void testFunction(void); // Declare a function prototype
Note that the extern keyword is not needed here, because the compiler can automatically tell that it's a function prototype declaration.
The complete file2.c should then look like
extern int testVariable; // This is a declaration of the variable
void testFunction(void); // Declare a function prototype
void main()
{
testVariable = 40;
testFunction();
}
When compiler copes with file2.c it knows nothing about existence of testVariable and about its type. And as result it can't generate code to interact with such object. And purpose of line like
extern int testVariable;
is to let compiler to know that somewhere such object exists and has type of int.
With functions we have no such problem because of next rule - if function is not defined - compiler assumes that it is defined somewhere like
int testFunction() { ... }
So you can pass any number of any arguments to it and try to obtain int return value. But if real function signature differs - you'll get an undefined behafiour at runtime. Because of this weakness such approach is considered as bad practice, and you should declare proper function prototype before any call to that func.

Confusion regarding extern with function definitions in C [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Effects of the `extern` keyword on C functions
Ok, so for a few hours now I've read a lot about what the extern keyword means. And there is one last thing that is bugging me to no end that I cannot find any info about.
As far as I understand the extern keyword basically tells the compiler that the variable or function is only a declaration and that it is defined somewhere, so it doesn't have to worry about that, the linker will handle it.
And the warning generated by the compiler (I'm using gcc 4.2.1) when typing this:
extern int var = 10;
supports this. With extern this should be a declaration only so it is not correct.
However, the thing that is confusing me is the absence of a warning or anything when typing this:
extern int func() {return 5;}
This is a definition, and it should generate the same warning, but it does not. The only explanation to this I was able to find here is that the definition overrides the extern keyword. However, following that logic why does it not override it when it is a variable definition? Or does the keyword have special meaning when used with variables?
I would be most grateful if someone explained this to me. Thank you!
The extern keyword indeed has special meaning only when it is used with variables. Using extern with function prototypes is entirely optional:
extern void foo(int bar);
is equivalent to
void foo(int bar);
When you declaring/defining a function, you have two options:
Provide only a declaration (i.e. a prototype), or
Provide a definition, which also serves as a declaration in the absence of a prototype.
With variables, however, you have three options:
Provide only a declaration,
Provide a definition with the default initializer: int var; without the = 10 part, or
Provide a definition with a specific initializer: int var = 10
Since there are only two options for functions, the compiler can distinguish between then without the use of extern keyword. Any declaration that does not have a static keywords is considered extern by default. Therefore, the extern keyword is ignored with all function declarations or definitions.
With variables, however, the keyword is needed to distinguish between the #1 and the #2. When you use extern, it's #1; when you do not use extern, it's #2. When you try to add extern to #3, it's a warning, because it remains a definition, and the extern is ignored.
All of this is somewhat simplified: you can provide declarations several times in the same compilation unit, and you can provide them at the global scope or at a block scope. For complete details, check section 6.7.9 5 of the C standard.
However, following that logic why does it not override it when it is a variable definition? Or does the keyword have special meaning when used with variables?
The difference between variables and functions is that
void foo();
is a function declaration, but
int i;
is a variable definition.
If you have the variable definition in multiple files, then the compiler will generate the storage for that variable multiple times (and most likely you'll get a linker error). This is not the case for functions.

Declaration Versus Definition in c

Recently while learning about c programming i noticed something that i found interesting. I had read that a statement like int i=0; is the only way to force a definition while a statement like extern int i; implies a forced declaration. A statement like int i; would be context dependent. But what happens when i combine the the extern with initialization like extern int i=13;. Compiler generates a warning. But what is this rule governing this?
This is a Coding style warning.
The argument for this is the code is valid, but extremely unidiomatic for C since "extern" is generally expected to mean that the declaration is not providing a definition of the object.
extern int i=13;
declares and defines i, While:
extern int i;
just declares the variable i.
A specific bug 45977 has been raised on GCC on the same but it is still shows Unconfirmed Status.
The bug report points out that the code is syntactically as per the C standard. And it has an discussion which discusses this in detail.
For Standerdese Fans:
Relevant Section References are:
ansi c99 Standard 6.2.2: Linkage Of Identifiers and
ansi c99 Standard 6.9.2.4
When you declare a variable you just bind a name to it.
When you define a variable you reserve memory for it.
When you declare a variable as extern you are telling the compiler "this is defined elsewhere and will be available on linking time", so it's OK to use it.
Extern is used if you want to access particular variable from different program. As you don't have any definition for that in you program your complier is giving you an error.
In C, a definition is just a declaration that happens to allocate storage (whether it is because it has an initializer, or because it is a tentative definition that gets used as a definition). So, everything that you can do to a declaration (like specifying it has extern storage), you can also do to a definition.
Note that this differs from C++.

Resources