C - extern, static, include - c

Scoping in C is confusing as hell. I have a variable: "int qwe". This var should be visible in one or more files - f1.c in this case, but not the another f2.c .
Say i have: main.c, f1.c, f2.c, header.h
main:
call f1();
call f2();
header:
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
int qwe = 1;
void f1();
void f2();
#endif // HEADER_INCLUDED
f1.c:
#include <stdio.h>
extern int qwe;
void f1(){
printf("In f1: %d\n", qwe);
}
f2.c:
#include <stdio.h>
static int qwe = 2;
void f2(){
printf("In f2: %d\n", qwe);
}
Now this gets confusing. There is definition and declaration. I have defined qwe in the header, declared it in f1.c. Is that correct? Should definition happen in header and declaration in f1.c instead? I tried the latter case, but got an error - "multiple definition of qwe". When i removed the #include directive from f1.c, it worked... It also works when i remove the extern keyword. Is extern redundant?
f2.c i guess it's ok and behaves as expected, or is it? But if i put an #include with header, it breaks. Why is that?
When should i use #include in source files? If i don't include it f1.c or f2.c it works...
Also, if i define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data. And next time that same function gets called, will have access to it, right? But the var won't be reinitialized to 0, i.e. the line where is defines won't execute. Correct?
Life stomps me :(

In the header, declare the variable. In e.g f1.c, define the variable, e.g. int qwe = 1; // at global scope.
In all files that want to see/change qwe, include the header that declares the variable. Easy-peasy.

You need to declare the variable in the header, and define it in one and only one C file.
In C, you cannot have a variable that doesn't "belong" to a given translation unit (source file). So it must be defined by exactly one translation unit in the whole program.
When you declare a variable as extern, you're telling the compiler the symbol is (possibly) external to your translation unit (c file).
It's probably also worth noting that when you try to declare a variable without extern, the variable is also defined, e.g.:
/* Declares, but does not defines external symbol 'foo' */
extern int foo;
/* Both declares AND defines bar */
int bar;
This is also different from how functions work to where the "default" syntax for declaration does NOT define a function:
/* Declare, but don't define spam */
void spam(void);
/* Declare, but don't define eggs */
extern void eggs(void);
/* Declare & define 'cheese' */
void cheese(void){ return; }
So your example should look more like this:
qwe.h:
#ifndef QWE_H
#define QWE_H
/* Declare qwe here */
extern int qwe;
#endif
f1.c:
/* DEFINE qwe here */
int qwe = 1;
f2.c:
#include "qwe.h" /*header includes the `extern int qwe` declaration */
void my_function(void)
{
/* use external symbol here! */
qwe = 10;
}

The scoping system isn't that confusing. The rule is this:
if you define something in a .c file EVERY other .c file in your program can access it (it is put in the global namespace).
if you specify static in front of its definition then only things in the SAME file can see it. This should be your default position for all functions and variables you don't want other .c files to be able to access.
It is very important to remember that extern only tells the compiler that the variable/function in question is not defined in the current file. This prevents the compiler for otherwise issuing an error because it can't find the symbol, but it has nothing to do with scoping - your .c file sees everything in the global namespace and if you have not followed the second part of the rule you will quickly find out about this at link time.
Header files similarly have nothing to do with scoping. They are just convenient places to put a bunch of extern statements and macros.

In C, you should use the header file in general to declare the data but not define the data. You don't want to define global data in a header because it will then be redundantly defined in multiple modules. The header indicates to multiple modules the existence of some data or function somewhere and what its type is, as well as common constants and macros (#defines). Outside of that, things in C are very simple. Just about anything is, technically, global unless you declare it static, keeping it scoped to the module it's defined in. The extern declarations for data in the headers and the function prototypes help the compiler know that these items are being accessed by a particular module and what the data types are for access so that the correct code can be generated.
You have:
Two functions f1 and f2 that are defined in separate modules but used in main. So these need to be declared in a header file.
A global data item qwe being used in more than one module.
A static qwe used in one module.
Assuming you want this done with one header file (you might need separate ones for f1, f2, and global data - see below), you could set up
your header as:
#ifndef MY_HEADER_H
#define MY_HEADER_H
extern int qwe;
void f1(void);
void f2(void);
#endif // MY_HEADER_H
Then in your main.c:
...
#include "my_header.h"
int qwe; // This is global and can be accessed from other modules
void main(...)
{
// call f1
// call f2
...
I just defined the global variable, qwe, in main.c arbitrarily. If you have a few globals, you can define them in their own glob_data.c module, for example, and have it's own header, glob_data.h, to declare them. Any other module that needs to access them would include the glob_data.h header so that compilation can properly be done on that module to access that data. Keeping the global data in separate headers helps with cases like you have where you have a static instance of the data versus the global, which are in conflict. You can avoid including the data header file for that global item when you want to compile with the static item.
Then in your C file, f1.c:
...system headers included...
#include "my_header.h"
void f1() {
printf("In f1: %d\n", qwe);
}
And in f2.c:
...system headers included...
#include "my_header.h" // Only if it doesn't contain `extern int qwe;`
static int qwe = 2; // This hides the global qwe and is known only
// to f2.c
void f2(){
printf("In f2: %d\n", qwe);
}
As I mentioned above, you might want to separate your function prototypes and your global data declaration in separate headers. That way, you can include only what's needed in each module and avoid conflicts, such as when you have a static int qwe; versus the global int qwe;.

I have defined qwe in the header, declared it in f1.c. Is that correct?
No, it should be the other way around. You are supposed to have a definition of a global variable in a single translation unit (that's geek speak for a .C file) but you may declare it in as many translation units as you wish. Since headers potentially get included from many translation units, declarations go in the headers.
When should i use #include in source files?
You do it when the header has anything that is needed for your translation unit to compile, with very few exceptions. Note that in some situations it may be necessary or desirable to make a forward declaration manually without including the header.
Also, if I define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data.
That is correct, the static variable inside the function will be assigned the initial value only once, and retain the value that you assign to it for as long as your program continues to run.

Related

static function declarations in header files

I have a static function in a source file that is used by other functions in that same source file. Is it fine to put the declaration for that static function in the header file, even though that header file will be included into other source files? Example:
/* foo.c */
#include "foo.h"
/* exported function; calls g */
void f(void) {
g();
}
static
void g(void) {
/* do something... */
}
/* foo.h */
void f(void);
void g(void);
/* main.c */
#include "foo.h"
int main(void) {
f();
}
Is it fine to put the declaration for that static function in the header file, even though that header file will be included into other source files?
No. Consider the conflict the other source files would have if they had a function/object/macro of the same name.
Even without conflict, an "unused function" warning may occur. #Adrian Mole
By putting static void g(void) in the .h file, it adds an unnecessary potential name conflict.
Simply declare/define that static function at the top of the .c in which it is used.
Is it fine to put the declaration for that static function in the
header file, even though that header file will be included into other
source files?
No. becuse it does not make any sense. and why?
In C, functions are global by default. Unlike global functions in C, access to static functions is restricted to the file where they are declared! Therefore, when we want to restrict access to functions, we make them static.
Another reason for making functions static can be reuse of the same function name in other files. so declaring them static in the header file can cause to name collisons in other source files.
In header files we declare our API functions those we want to expose only. in c files we declare usually auxilary functions as static functions for restricting the scope of those aux functions to the c file only

Header variable turn to zero

I am using STM32F103 and and Keil for the Compiler. Here is my summary code:
There is a header file like abc.h and abc file has a static variable. abc.h is like that:
static uint8 a;
And there is a function in another header file which named abcd.h and that changes the a' s value.
abcd.h header file is like that.
include "abc.h"
void foo()
{
a = 0x0A;
}
My issue is that:
When I call the "foo" fuction in main "a" is turn to zero even if I assign the "a" variable to 0x0A in "foo()" function. By the way, If I define the "a" variable with extern and the problem does not occured. I mean "a" is get 0x0A value.
Is there anyone the help me why does this problem occur.
Some rules of thumb:
Never declare global variables. (extern ones)
Never declare variables inside header files.
static variables are per definition not global, but could be "file scope" - that is, visible to the file they are declared inside. Or more accurately, visible inside the translation unit they are declared inside, a translation unit meaning a specific .c file and all the headers that .c file includes.
So if you declare a static variable in a header, which is included by two different .c files, then you end up with multiple local copies of the variable. If you are lucky, you get a linker error, but the linker may as well attempt some internal "name mangling". The very meaning of static is to prevent access to the variable by other files.
The best solution to this is to use setter/getter functions:
// abc.h
#ifndef ABC_H // always use "header guards"
#define ABC_H
uint8_t get_a (void);
void set_a (uint8_t n);
#endif
-
// abc.c
#include "abc.h"
static uint8_t a;
uint8_t get_a (void)
{
return a;
}
void set_a (uint8_t n)
{
a = n;
}
That is how you should be doing in the vast majority of cases. Using extern should be avoided, but for the rare cases when you have to use it, then use it like this:
// abc.h
#ifndef ABC_H // always use "header guards"
#define ABC_H
extern uint8_t a;
#endif
-
// abc.c
#include "abc.h"
uint8_t a;

Access global variable value in different .c files present in different paths

I have 2 files: Sod/iload/iload.c and
Item/itemrule/itemrule.c, and I want to access a variable defined in iload.c which is defined in itemrule.c.
To do this, I made and defined a global variable in iload.c, and I tried to access this variable in itemrule .c with the extern keyword, but it is always 0.
I'm worried that it might be because the files have different paths, does anyone know how I can access this variable?
The usual idiom is to use an extern declaration in a header file and include that wherever the global is needed.
// foo.h
// Make the global visible in any C file that includes this header.
extern int my_global_var;
// foo.c
#include "foo.h" // Not really needed here, but fine.
int my_global_var;
...
// bar.c
#include <stdio.h>
#include "foo.h" // This one makes the global visible in the rest of the file.
void do_something(void) {
printf("my global var's value is: %d\n", my_global_var);
}
Note that using globals like this in a program of any significant size or complexity can lead to messy, bug-prone, and hard-to-change code. Not a great pattern to follow.
I would like to offer an alternative to Gene's answer. In my experience there are two main ways to share variables across modules (compilation units):
1) "Getters and Setters".
2) Externs.
Depending on what kind of team you're working with, they'll have a preference for one or the other. C functions by default have external linkage; you need to force internal linkage via the static keyword in front of the function name if you don't want this.
1) Getters and Setters:
// foo.c
#include <stdio.h>
int my_global_var = 0;
...
Then you can follow it with externally-linked getters and setters. i.e.:
int get_my_global_var(void)
{
return my_global_var;
}
void set_my_global_var(int var)
{
my_global_var = var;
}
This is done within the c file (module). It will be the getters and setters will be able to be called from any other module and they will get and set the global variable my_global_var.
2) Externs:
// foo.c
#include <stdio.h>
int my_global_var = 0;
...
An alternative to getters and setters is to use externs. In this case you add nothing extra to the module that contains the global variable you wish to access/modify (my_global_var).
// bar.c
#include <stdio.h>
extern int my_global_var;
...
Notice the syntax here; when we use the extern keyword, we don't initialize it as anything. We are simply infoming the compiler that the global variable my_global_var has external linkage.

Globals declared in h file and access to them

Just a simple question for understanding:
variable extern int x_glob is declared in header glob.h.
so in every c file that contains functions declared in glob.h using this variable I have to define it agin like this:
extern void func_1( void )
{
int x_glob;
glob_x++;
return();
}
Is that correct?
If I leave off the extern word on the declaration of x_glob in glob.h, I don't need the definition.
Why not leaving away the extern word in the header file?
Maybe this question sounds stupid - my goal is to get a better structure into
my programming as the projects grow.
No, this is wrong. With int x_glob inside a function you declare a local, automatic variable. This overrides any global variable.
But in precisely one .c file you must declare the global variable:
// main.c
int x_glob;
This creates one variable that can now be used by all modules. The extern version of the variable only tells the compiler when compiling the other modules that somewhere there exists this variable and it will be found upon linking the modules into the excutable.
Personally I prefer the following set-up:
// glob.h
#ifndef EXTERN
#define EXTERN extern
#endif
EXTERN int x_glob;
// module.c
#include "glob.h"
// main.c
#define EXTERN
#include "glob.h"
In all modules x_glob will be known as extern and in main it will not be extern and so will declare the storage for the global variable.

Warnings while organising variables and functions in C over multiple header and source files

For the first time i was trying to write an actual professional C code for a simple program.
1)I made a header file name Essential_data.h and declared all my functions and global variables in that. I had declared all my variables as extern.. And all function declaration were made normally
eg:
void test ();
extern int x;
2)Then i made another header file named main_data.h and defined all my global variables there.
for eg:int x;
3)I then made corresponding source files containing the definition of the respective functions and included main_data.h in sourcefiles that needed that global variable.
thats all. After when i compiled the project i got many warnings for all functions as
Implicit declaration of function test [-Wimplicit-function-declaration]
so after that i did the following
1) I put an extern in front of the functions declarations in Essential_data.h.
for eg:
extern void test();
2) in the main_data.h i declared the functions normally and wrote
void test ();
both the times my Essential_data.h was in the main function only and no where else.
And then recompiled and later all the warnings disappeared.
So was that the right method or is there any other way of organising them more efficiently?
You should have:
One or more .h files containing extern declarations (functions and objects). These files needs to be included by the .c files that need those symbols. You shouldn't have multiple declarations (each identifier should be declared exactly once)
One or more .c files in which you define the functions and objects
In your example:
/* essential_data.h */
void test ();
extern int x;
/* something.c */
#include "essential_data.h"
int x;
void test()
{
/* ... */
}
/* main.c */
#include "essential_data.h"
/* ... */

Resources