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;
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 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.
Pardon me, I am not very good in explaining questions. So I start with example directly
Look at following example
const int a=10;
int *ptr;
int main(){
ptr=&a;
*ptr=100; // program crashes
printf("%d",a);
}
But If I made a slightly change in above code as following
const int a; // uninitialized global variable
Then the above code works fine.
So my question is why compiler behaves differently for uninitialize and initialize global const variables?
I am using gcc for windows (mingw).
You are modifying a const object, and that is simply undefined behavior - so don't do it, and don't ignore compiler warnings.
Now, the actual reason for the different behavior in your particular case is that for const int a=10; the value 10 has to be stored somewhere. Since the variable is const, the linker places it in the .rodata or a similar read only section of the executable. When you're trying to write to a read-only location, you'll get a segmentation fault.
For the uninitialized case, const int a , the a needs to be initialized to zero since it's at file scope (or; a is a global variable). The linker then places the variable in the .bss section, together with other data that also is zero initialized at program startup. The .bss section is read/write and you get no segfault when you try to write to it.
All this is not something you can rely on , this could change with minor modification to the code, if you use another compiler or a newer/older version of your compiler etc.
Global and static variables are initialized implicitly if your code doesn't do it explicitly as mandated by the C standard.
From the doc:
const is a type qualifier. The other type qualifier is volatile. The
purpose of const is to announce objects that may be placed in
read-only memory, and perhaps to increase opportunities for
optimization.
In G++ you will receive the error for the second case ie, const int a;.
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.
declares a constant integer variable. It means it’s value can’t be modified. It’s value is initially assigned to 10.
If you try to change its value later, the compiler will issue a warning, or an error, depending on your compiler settings.
I'm experiencing some weird behaviour (well, i guess it's got an explanation) while trying to cross compile some Files from Debian to an arm-linux target, using:
$ arm-linux-gnueabi-gcc --version
$ arm-linux-gnueabi-gcc (Debian 4.3.5-4) 4.3.5
While compiling I get these error messages:
dsblock1.c:167: error: non-static declaration of ‘HaveEventIterated_’ follows static declaration
ss2dym.c:778: error: previous declaration of ‘HaveEventIterated_’ was here
The corresponding Lines are:
ss2dym.c:778 :
extern long HaveEventIterated_;
"redeclaration" dsblock1.c:167:
long HaveEventIterated_=0;
So here's the thing i don't get:
according to what i thought i knew, variables first declared extern, are non-statics.
BUT: the "extern" declaration is inside a static function.
So my guess is, that this is some kind of inherited behaviour?!
So here are the questions:
- can someone explain the background story, IF my guess is correct?
- is there an easy way to get around that, e.g. with a tricky compiler-flag that allows nested scope-shifting or some other magic?
I know it would most likely possible to create a header and put all those extern declarations into neutral space, but i've got like hundreds of those errors and several files. And i've seen that this code compiles well using MSVC++ (that has other scope constraints, i know, but i have a lot more problems using arm-g++) so there must be some kind of solution, easier than just rewriting all those parts...
BTW: there is an easy way to change the scope of all those "redeclarations" since i have a macro in front of all of them like:
MY_MACRO long HaveEventIterated_=0;
and atm i compile with -DMY_MACRO=
Soooo anyone? :)
The extern keyword gives identifiers the same linkage1 as a previous visible declaration, or external linkage if there is no previous visible declaration. (This is a weird quirk of the language, to be sure.)
Thus, the problem is most likely occurring due to a third (or perhaps I should say "first") declaration of HaveEventIterated_, that the compiler is reaching before it reaches line 778 of ss2dym.c. That third (or first) declaration uses the static keyword to give the identifier internal linkage. The second declaration, with extern, then gives the same variable internal linkage, and the third—with no storage-class keyword to specify linkage—gives the variable external linkage, resulting in the error.
Here's a short example that reproduces the issue (in a different gcc, but the same behavior):
$ cat foo2.c
static int var;
extern int var;
int var = 0;
$ gcc -c foo2.c
foo2.c:3: error: non-static declaration of 'var' follows static declaration
foo2.c:2: error: previous declaration of 'var' was here
1Side note: if the previous visible declaration has no linkage, you get external linkage. This only occurs when re-declaring a variable inside a block where the variable outside that block has automatic duration, i.e., is a "local" or "stack" variable inside a function:
void f(void) {
int v;
{
extern int v;
Here there's a previous visible declaration with no linkage, so the innermost v has external linkage. If there is a v with internal linkage in the same translation unit, the effect is undefined. (Of course no one should write code like f() in the first place, anyway :-) )
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.