Extern makes no difference - c

I am defining a global variable in test2.h
#ifndef TEST2_H
#define TEST2_H
int test_var;
void use_it(void);
#endif
and defining it again in two different files, test.c
#include <stdio.h>
#include "test2.h"
int test_var;
int main() {
printf("The test_var is: %d\n", ++test_var); // prints 1
use_it(); // prints 2
}
and test2.c
#include <stdio.h>
#include "test2.h"
int test_var;
void use_it() {
printf("The test_var is: %d", ++test_var);
}
I replaced the definition of test_var with extern int test_var and got the same result. That is, in both cases both files, test.c and test2.c have access to the global variable test_var. I was under the impression that without extern, each file would have their own copy of test_var. Observation suggests that this is not the case. So when does extern actually do something?

You end up with two copies of test_var and this is undefined behavior.
(C99, 6.9p5) "If an identifier declared with external linkage is used in an expression (other than as part of the operandof 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"
In your case the linker may be nice with you and merges the two symbols but this is still not portable and is undefined behavior. If you are using the GNU linker, you can use --warn-common to get the warning (and --fatal-warnings if you want an error).
To fix your issue, put the extern specifier in the declaration of test_var in the .h file and remove one of the definition of test_var (for example the one in test.c file).

This is undefined behavior, as others have noted, but what you are seeing here is the common extension described in appendix J.5.11 of the C99 spec, where multiple external definitions in different compilation units are allowed as long as none or only one of them are initialized and the types of all of them are the same.
In this case, with the extension, the definitions will be combined into a single definition at link time.
You also appear to be confused by the fact that the extern keyword, when used at the global scope, has nothing to do with extern linkage for declarations and definitions. ALL declarations at the global scope have extern linkage unless they have a static or inline keyword. The extern keyword serves to make such a declaration just a declaration. Without the extern keyword a global variable declaration is also a definition, and that is the only effect of the extern keyword in the global scope.

If you have the same variable declared in 2 diferent files as int test_var for example:
file1.c
int test_var;
file2.c
int test_var;
both variables will have their own memory adress, so they are two diferent variables with the same name.
if you have, two variables declared in 2 diferent files declared as extern int test_var, for example:
file1.c
extern int test_var; //this is a mistake
file2.c
extern int test_var; //this is a mistake
the compiler will return an error when you try to do something with that variables because with the keyword externyou are not reserving any space for that variable, you only use that keyword to say that a variable is already defined (commonly in another file).
The point is to unsderstand that a global variable is defined once with a sentence like int test_var (when you define a variable the compiler reserve space for it) and it's declared in every other file that need access to it with extern int test_var (when you declare a variable with the extern keyword you saying the compiler that variable is already defined and you want to have access to it in the file you are declaring it).
So an example of how to use a global variable wil be:
file1.c
int test_var; //definition
void useit(void);
int main () {
test_var=7;
useit();
return 0;
}
file2.c
#include <stdio.h>
void useit (void) {
extern int test_var; //declaration
printf ("the variable value is %d",test_var);
}

To answer your question:
extern int test_var; is a declaration. This announces that "Somewhere, there should exist test_var . We don't know where that is yet, but by the time we finish compiling and linking, we will find it in exactly one place".
So there has to be exactly one definition to match. A definition serves as a declaration, and also says "Here is the storage for test_var".
Also, test_var could either have internal linkage or external linkage. The default behaviour is external linkage. If you provide more than one definition for a variable of external linkage, it is undefined behaviour.
Internal linkage is indicated by including static in the declaration. You can have as many definitions as you want of a static variable (so long as only one per file has an initializer).
Summing up, we have:
extern int test_var; // declaration, external linkage
static int test_var; // declaration, definition, internal linkage
int test_var; // declaration, definition, external linkage
Note: the last two cases are actually tentative definitions: this is a thing that C has but C++ doesn't; the way it works is that it behaves like a declaration at first; but then , for each unit, if there is no later definition then this actually serves as a definition.
So you can write in C:
int test_var;
// stuff
int test_var = 5;

If you are using gcc and possibly some other compilers, you just stumbled upon some Unix tradition. Namely that uninitialized global variables are placed in the common block where multiple definitions of the same variable are merged during linking.
gcc can be told to put uninitialized global variables into the data section with the option -fno-common. With this, the linker will report an error when there are multiple definitions of the same variable name.

Related

What a C static variable in file scope means?

I have three files to demonstrate the use of static variable in file scope. Variable is declared as extern in file2.h, initialized in file2.c. I am declaring another variable with same name in main.c as static to test for static global scope. But I get the error message "main.c|6|error: static declaration of 'var1' follows non-static declaration.
Could someone explain me the usage of static for file scope?
If I do not include file2.h in main.c, I do not get any problem. But what if I need to use some functions of other files in main.c but still want to keep the variable scope to this file only?
main.c
#include <stdio.h>
#include "file2.h"
static int var1;
int main()
{
printf("value of staticVar1 = %d\n",var1);
func1();
printf("value of staticVar1 after function call= %d\n",var1);
return 0;
}
file2.h
#ifndef _FILE2_H
#define _FILE2_H
#include <stdio.h>
extern int var1;
int func1(void);
#endif // _FILE2_H
file2.c
#include <stdio.h>
#include "file2.h"
int var1=3;
int func1(void)
{
printf("value of staticVar1 inside the function = %d\n",var1);
return(0);
}
An object declared at file scope has either external or internal linkage, it cannot have both linkages:
extern int var1; // declare var1 an int with external linkage
int var1 = 3; // declare and define var1 with external linkage
static int var1; // declare and define var1 an int with internal linkage
// -> ERROR var1 is redeclared with different linkage
You use static specifier if you want an object with visibility limited to the source file in which you declared it.
#include literally includes the text of its argument. If you include "file2.h", the top of your main.c will have both
extern int var1;
and
static int var1;.
The compiler won't be able to tell whether you want var1 to be
extern (=make it an as-of-yet nonresolved reference to a global scope variable defined with inter-file visibility later or in some other/external compilation unit)
or
static (=place the symbol here but hide it from other compilation units).
Edit: A more nuanced view of static/extern described here: Using a variable in a file with extern keyword which is defined as static as well as global in the base file?. The caveat is that extern may not make a variable have "external linkage"—it can copy previous linkage (static int x; extern int x /*x is static because of the previous declaration; and you may run into undefined behavior if you use extern at block scope and there are intervening overshadowing variables.)
If you declare var1 static inside of your main.c it means that this variable shall only be available in this files's compilation unit.
It also allows to declare a
static int var1
in each of your .c files without having a conflict because the variable is not exported or made visible to other compilation units / .c files.
extern int var1
is somewhat the opposite of the static declaration. It says that the var1 variable is not declared here but somewhere else.
You would use extern for instance if you have one example.c file where you declare
int var1
and serveral other .c files where you also want to set and read values of that exact variable from example.c.
In those .c files you would then declare the variable
extern int var1
telling the compiler that the variable var1 exists but is not declared here.
if you forget to really declare the variable inside of example.c but use it with extern in other .c files, you should get a undefined reference error, i think, because variable existance in that case is checked at link time
Putting the external declaration on the header and having the definition on exactly one source file will do. Remove
static int var1;
and you should be fine. You're qualifying a variable with two orthogonal properties: static and extern. The former is to say it'll be visible only within and the latter is to say it'll be referred to externally. This is the reason you see the error.
Could someone explain me the usage of static for file scope?
It means whatever is static will have internal linkage. No other TUs will be able to see this symbol outside of the one you've defined it on.
what if I need to use some functions of other files in main.c but still want to keep the variable scope to this file only?
Remove the extern declaration from the header and keep the variable only in main.c.

Declaring global variables in the header file or the C source file

I am kind of confused about the whole including header files and declaration of variables.
Files I am using are: main.c, lib.h and lib.c.
main.c
#include "lib.h"
void main(void)
{
// Code here
var++;
}
lib.c
#include <avr/io.h>
#include "lib.h"
void light_led(void)
{
// Code here
}
lib.h
volatile int var;
void light_led(void);
Is this the correct way of making and including your own custom-made libraries?
You should use extern keyword for such cases and not define global variables in headers. Otherwise the linker will throw errors when operating on your header files.
lib.c
#include <avr/io.h>
#include "lib.h"
volatile int var;
void light_led(void)
{
//code here
}
lib.h
extern volatile int var;
void light_led(void);
This way you'll be declaring the global variable in headers and actually defining it in the appropriate source file lib.c.
Note: Notice the difference between declaring and defining a variable. extern keyword allows the variable to be declared in advance without being defined. Had you not defined the variable in lib.c, there would be an error when you tried to use this variable. Since, it is only declared but, not actually defined.
Edit: The whole purpose of static is to declare that a variable is private to the source file that is declared in. Since, extern does the opposite by linking a variable defined in another source file, it defeats the purpose of static. extern says the variable has external linkage static says the variable has internal linkage. An identifier can't have both internal and external linkage.
According to MSND:
When modifying a variable, the static keyword specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends) and initializes it to 0 unless another value is specified. When modifying a variable or function at file scope, the static keyword specifies that the variable or function has internal linkage (its name is not visible from outside the file in which it is declared).
For more information check below:
Understanding "extern" keyword in C
Why we need "extern keyword in C

static declaration of m follows non-static declaration

I am trying a small example to know about the static external variable and its uses. The static variable is of local scope and the external variable is of global scope.
static5.c
#include<stdio.h>
#include "static5.h"
static int m = 25;
int main(){
func(10);
return 0;
}
static5.h
#include<stdio.h>
int func(val){
extern int m;
m = m + val;
printf("\n value is : %d \n",m);
}
gcc static5.c static5.h
o/p :
static5.c:3: error: static declaration of m follows non-static declaration
static5.h:3: note: previous declaration of m was here
EDITED
The correct program :
a.c:
#include<stdio.h>
#include "a1_1.h"
int main(){
func(20);
return 0;
}
a1.h:
static int i = 20;
a1_1.h:
#include "a1.h"
int func(val){
extern int i;
i = i + val;
printf("\n i : %d \n",i);
}
This works fine perfectly fine. But this is compiled into a single compilation unit. Hence could able to access the static variable . Across the compilation unit we cannot use the static variable by using the extern variable.
static has a very simple logic to it. If a variable is static, it means that it is a global variable, but it's scope is limited to where it is defined (i.e. only visible there). For example:
Outside a function: global variable but visible only within the file (actually, the compilation unit)
Inside a function: global variable but visible only within the function
(C++) Inside a class: global variable but visible only to the class
Now let's see what the C11 standard says regarding static and extern (emphasis mine):
6.2.2.3
If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
6.2.2.4
For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, 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.
6.2.2.7
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
So the standard says that first, if you have:
static int m;
extern int m;
then the second declaration (with extern) would regard the first one and in the end m would still be static.
However, in any other case, if there are declarations with both internal and external linkage, the behavior is undefined. This actually leaves us with only one option:
extern int m;
static int m;
i.e., extern declaration before static declaration. gcc was nice enough to give you error in this case of undefined behavior.
Remember this (quoting Eli Bendersky):
A static variable inside a function keeps its value between
invocations.
A static global variable or a function is "seen" only in
the file it's declared in
In your code, static int m = 25; means that m's scope is limited only to that file, that is, it is only visible inside static5.c and nowhere else.
If you would like to make use of m outside of static5.c make sure to remove the keyword static from the declaration of the variable.
For a more canonical explanation, along with an example, see this answer by Eli Bendersky
EDIT: (according to Klas' recommendation) **The actual scope is a compilation unit, not the source file. The compilation unit is the way the file looks after the preprocessor step
The problem is exactly as stated in the error message. m is declared a normal int but is later defined as a static int.
extern tells the compiler/linker to look for the variable in the global table of variables.
static (outside a functon) tells the compiler to exclude the variable from the global table of variables.
Do you see the conflict?
To fix the problem, either remove the static keyword from the definition or move the definition above the inclusion of static5.h.
It should be noted that the way you have designed your files is not considered best practice. Include files don't usually contain functions.
remove the keyword static while declaring m and the errors will be removed and you will be able to get the answer as 50. The static keyword makes the scope to restrict within the file.

extern with global definition of variable in 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;

C - Static variable masking global variable

Have a look at the following code snippet...
File1.h
void somefunc(int);
File1.c
#include "File1.h"
extern int var;
void somefunc(int x)
{
......
var ++;
etc, etc,
....
return;
}
File2.h
static int var;
void someotherfunc(int);
File2.c
#include "File2.h"
#include "File1.h"
int var;
void someotherfunc(int z)
{
z = etc etc;
var --;
......
somefunc(z);
.....
return;
}
The above four files compile without any problem.
The problem occurs when i try to initialize the variable 'var'.
If the 'var' is initialized in the File2.c where it is a global variable, the code compiles without any problems. But when i try to initialize the static variable in File2.h, the compiler throws an error saying 'the variable 'var' in File1.c is undefined'. Can someone please tell what is happening here.
I was just trying to understand the concept of static variables and came upon this confusion. Any help would be appreciated.
static int var;
This gives var internal linkage in the File2.c translation unit, whatever might follow (yes, even if the extern declaration follows).
So if the first declaration seen is static int var, in that translation unit var will forever be internal, thus inaccessible to other translation units.
6.2.2-4
For an identifier declared with the storage-class specifier extern
[File1.h] in a scope in which a prior declaration of that
identifier is visible [the one in File2.h] if the prior declaration
specifies internal or external linkage [it specifies internal], the linkage of the identifier at > the later declaration is the same as the linkage specified at the
prior declaration.
It can't be static. Static means its "visibility" (not the official term but probably more understandable) is limited to the C source file it appears in (in this case, that's File2.c).
That means, when you try to link together File1 and File2, the linker will not be able to see var in File2, which is why you're getting the error.
If you want it accessible from File1.c, ditch the "static" bit. In fact, since you already have var defined in File2.c, ditch the entire line from File2.h.

Resources