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.
Related
I'm getting my sea legs with C, and I need a string literal which is discovered in a main function in one .c file to be accessible in an entirely different .c file.
What I've tried: I'm declaring a pointer to a string literal as extern in a header, defining it on one .c file, and trying to access the literal in a second .c file. Compilation is failing due to lack of definition in the second (accessing) file.
What I've got in a nutshell:
file1.h :
extern char *global;
file1.c :
#include "file1.h"
int main() {
//some code
extern char *global = some_struct->data;
//more code
}
file2.c :
#include "file1.h"
int do_stuff() {
//some code
some_function(global);
//more code
}
I expected this to compile, since global is declared in file1.h, defined in file1.c, and its value accessed in file2.c. Compilation of file2.c fails, however, for undefined variable.
If relevant, the main function in file1.c is always the first function run in the program.
in main
extern char *global = some_struct->data;
is wrong, if you want to assign global do :
global = some_struct->data;
and some where at global scope you need to define global :
char *global;
So for instance main become :
#include "file1.h"
char *global;
int main() {
//some code
global = some_struct->data;
//more code
}
You're close, but not quite there. The global variable must also be defined in the global scope, and you're running into the difference between declaration and definition (which are easy to get the wrong way round but the words don't matter as much as the idea). Normally, your statements that introduce a variable will both declare and define simultaneously, but not so with globals that are shared between modules like this:
In your file1.h, you are correctly declaring the char* variable in the global scope. Anyone who includes this file (e.g. file2.c) will "see" that the variable with that name should exist and all modules will compile cleanly, and the extern keyword makes explicit that you are only declaring this to exist, not creating storage for it yet. That is what you want, because you don't want to accidentally create multiple conflicting global variables with this name. When the compiled modules are eventually linked together, the linker will look for the actual memory storage space set aside for the global and connect all the references up correctly.
But in your case, that won't happen correctly, because although you have declared to the world that this global exists, you haven't yet actually created storage for the variable!
You still need to do this in the global scope (outside the functions) in file1.h:
char * global;
That creates the actual variable with the matching name to the extern declaration, and so the linker will be able to assemble your modules correctly.
So
#include "file1.h"
// Define global:
char * global;
int main() {
// Assign a value to the global variable:
global = some_struct->data;
//more code
}
Note that you don't redeclare the extern or anything in this file, and you don't redefine the type of global inside main, because it already exists, and you can assign to it or look at its value. You also don't use the keyword extern here-- it is the "home" module for this variable.
Declaration and definition are generally just accomplished simultaneously, for example when you declare local variables within a function. Globals that are accessible from different modules rely on splitting the work into the two separate ideas so that both coworkers and the compiler and linker toolchain are not confused by your intentions.
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.
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.
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.
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