What a C static variable in file scope means? - c

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.

Related

variable with file scope in C without static keyword

In the below code, I removed the word extern from variable declaration for var10 in file2.c I was expecting that the variable var10 in two files are independent of each other and both have file scope when extern is not used in one of the files. But the result is 10 and 34 instead of 10 and 10 as I was expecting. So we cannot have a variable with file scope without using static keyword? Why we do not get multiple definition error in case scope of both the variables is same? I use codeblcoks+mingw
file1.c
#include <stdio.h>
int var10;
int main (void)
{
var10=10;
printf("Var10 before function call=%d\n",var10);
var10TestFunc2();
printf("Var10 after function call=%d\n",var10);
}
file2.c
#include<stdio.h>
int var10;
void var10TestFunc2(void)
{
var10 = 34;
}
Global variables without static have global scope by default. Here you have defined the the same variable(without initialisation). One is considered as the definition and the other as declaration by the compiler.
If you initialize the variable with two different values in the definitions itself. It will cause linker error.

Extern makes no difference

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.

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

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.

Can we really restrict the scope of a global variable using Static?

I have read somewhere that we can restrict the scope of global variable to a file only by
using static keyword before variable name. But, when i tried it practically it comes out to be false:
//1st file - file1.c //2nd file - file2.h
#include<file2.h> static int a;
main()
{
fun();
}
fun()
{
printf("%d",a);
}
O/P is 0
Now we do have a global variable a which is declared in file2.h, whose scope is limited to this file only.
Since, we have declared it as static, but still we can access this variable in file1.c. How ??
In restrict the scope of global variable to a file statement, by file they mean compilation unit, i.e. a .c file. Your file2.h is included by file1.c and they constitute one compilation unit file1.
Move the variable to a second compilation unit e.g. file2.c, and you'll see you can't access it even with extern declaration.
The scope is not restricted to a file, but to a translation unit. Since you include file2.h into file1.c, this is all one TU -- you might as well have pasted the content of file2.h into the source file.
You are including the file file2.h in which you declared the variable as static in the c file which has main, which is as good as writing the declaration in that c file.
When you include a header file which declares a static variable a copy of the variable gets created for each translation unit(c file + included header files) in which the header file is included.
Never declare your static variables in header file.
To test the scenario, You should do this:
//file1.c
static int i = 10;
//file2.c
extern int i;
int main()
{
int a = i;
return 0;
}
Scope is defined after C's pre-processor has run. Ie: after all #include-statements have been evaluated and inlined.

Resources