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++.
Related
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.
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).
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.
I have seen static structure declarations quite often in a driver code I have been asked to modify.
I tried looking for information as to why structs are declared static and the motivation of doing so.
Can anyone of you please help me understand this?
The static keyword in C has several effects, depending on the context it's applied to.
when applied to a variable declared inside a function, the value of that variable will be preserved between function calls.
when applied to a variable declared outside a function, or to a function, the visibility of that variable or function is limited to the "translation unit" it's declared in - ie the file itself. For variables this boils down to a kind of "locally visible global variable".
Both usages are pretty common in relatively low-level code like drivers.
The former, and the latter when applied to variables, allow functions to retain a notion of state between calls, which can be very useful, but this can also cause all kinds of nasty problems when the code is being used in any context where it is being used concurrently, either by multiple threads or by multiple callers. If you cannot guarantee that the code will strictly be called in sequence by one "user", you can pass a kind of "context" structure that's being maintained by the caller on each call.
The latter, applied to functions, allows a programmer to make the function invisible from outside of the module, and it MAY be somewhat faster with some compilers for certain architectures because the compiler knows it doesn't have to make the variable/function available outside the module - allowing the function to be inlined for example.
Something that apparently all other answers seem to miss: static is and specifies also a storage duration for an object, along with automatic (local variables) and allocated (memory returned by malloc and friends).
Objects with static storage duration are initialized before main() starts, either with the initializer specified, or, if none was given, as if 0 had been assigned to it (for structs and arrays this goes for each member and recursively).
The second property static sets for an identifier, is its linkage, which is a concept used at link time and tells the linker which identifiers refer to the same object. The static keyword makes an identifier have internal linkage, which means it cannot refer to identifiers of the same name in another translation unit.
And to be pedantic about all the sloppy answers I've read before: a static variable can not be referenced everyhere in the file it is declared. Its scope is only from its declaration (which can be between function definitions) to the end of the source file--or even smaller, to the end of the enclosing block.
struct variable
For a struct variable like static struct S s;, this has been widely discussed at: What does "static" mean in C?
struct definition: no effect:
static struct S { int i; int j; };
is the exact same as:
struct S { int i; int j; };
so never use it. GCC 4.8 raises a warning if you do it.
This is because struct definitions have no storage, and do no generate symbols in object files like variables and functions. Just try compiling and decompiling:
struct S { int i; int j; };
int i;
with:
gcc -c main.c
nm main.o
and you will see that there is no S symbol, but there is an i symbol.
The compiler simply uses definitions to calculate the offset of fields at compile time.
This is struct definitions are usually included in headers: they won't generate multiple separate data, even if included multiple times.
The same goes for enum.
C++ struct definition: deprecated in C++11
C++11 N3337 standard draft Annex C 7.1.1:
Change: In C ++, the static or extern specifiers can only be applied to names of objects or functions
Using these specifiers with type declarations is illegal in C ++. In C, these specifiers are ignored when used
on type declarations.
See also: https://stackoverflow.com/a/31201984/895245
If you declare a variable as being static, it is visible only in that translation unit (if globally declared) or retains its value from call to call (if declared inside a function).
In your case I guess it is the first case. In that case, probably the programmer didn't want the structure to be visible from other files.
The static modifier for the struct limits the scope of visibility of the structure to the current translation unit (i.e. the file).
NOTE: This answer assumes (as other responders have indicated) that your declaration is not within a function.
It appears to me that even if I refer to a function in another file with out extern declaration, gcc can still compile that unit. So I am wondering whether the extern declaration is necessary anywhere for function? I know that you need extern for variables.
functions have extern storage class specifier by default (unless they are explicitly defined as static)
extern Storage Class Specifier
If the declaration describes a function or appears outside a function and describes an object with external linkage, the keyword extern is optional. If you do not specify a storage class specifier, the function is assumed to have external linkage.
....
It is an error to include a declaration for the same function with the storage class specifier static before the declaration with no storage class specifier because of the incompatible declarations. Including the extern storage class specifier on the original declaration is valid and the function has internal linkage.
It's not necessary, but I prefer it in headers to reinforce the idea that this function is defined somewhere else.
To me, this:
int func(int i);
is a forward declaration of a function that will be needed later, while this:
extern int func(int i);
is a declaration of a function that will be used here, but defined elsewhere.
The two lines are functionally identical, but I use the extern keyword to document the difference, and for consistency with regular variables (where the difference is important, and has exactly that meaning).
You do not necessarily "need" extern for variables.
When C was invented Unix linkers were also written, and they advanced the art in unheralded but clever ways. One contribution was defining all symbols as small "common blocks". This allowed a single syntax for declarations with no required specification of which module was allocating the space. (Only one module could actually initialize the object, but no one was required to.)
There are really three considerations.
Forward declarations for prototypes. (Optional, because legacy C has to compile without them.)
Extern declarations for non-function objects (variables) in all files except one. (Needed only on non-Unix systems that also have crummy linkers. Hopefully this is rare these days.)
For functions, extern is already the assumption if no function body is present to form a definition.
As far as I remember the standard, all function declarations are considered as "extern" by default, so there is no need to specify it explicitly.
That doesn't make this keyword useless since it can also be used with variables (and it that case - it's the only solution to solve linkage problems). But with the functions - yes, it's optional.
A little more verbose answer is that it allows you to use variables compiled in another source code file, but doesn't reserve memory for the variable. So, to utilise extern, you have to have a source code file or a library unit that contains memory space for the variable on the top level (not within functions). Now, you can refer to that variable by defining an extern variable of the same name in your other source code files.
In general, the use of extern definition should be avoided. They lead easily to unmanagable code and errors that hard to locate. Of course, there are examples where other solutions would be impractical, but they are rare. For example, stdin and stdout are macros that are mapped to an extern array variable of type FILE* in stdin.h; memory space for this array is in a standard C-library unit.