You should not define global variables in header files. You should define them in .c source file.
If global variable is to be visible within only one .c file, you should declare it static.
If global variable is to be used across multiple .c files, you should not declare it static. Instead you should declare it extern in header file included by all .c files that need it.
Example:
example.h
extern int global_foo;foo.c
#include "example.h" int global_foo = 0; static int local_foo = 0; int foo_function() { /* sees: global_foo and local_foo cannot see: local_bar */ return 0; }bar.c
#include "example.h" static int local_bar = 0; static int local_foo = 0; int bar_function() { /* sees: global_foo, local_bar */ /* sees also local_foo, but it's not the same local_foo as in foo.c it's another variable which happen to have the same name. this function cannot access local_foo defined in foo.c */ return 0; }
You should not define global variables in header files. You should define them in .c source file.
If global variable is to be visible within only one .c file, you should declare it static.
If global variable is to be used across multiple .c files, you should not declare it static. Instead you should declare it extern in header file included by all .c files that need it.
Example:
example.h
extern int global_foo;foo.c
#include "example.h" int global_foo = 0; static int local_foo = 0; int foo_function() { /* sees: global_foo and local_foo cannot see: local_bar */ return 0; }bar.c
#include "example.h" static int local_bar = 0; static int local_foo = 0; int bar_function() { /* sees: global_foo, local_bar */ /* sees also local_foo, but it's not the same local_foo as in foo.c it's another variable which happen to have the same name. this function cannot access local_foo defined in foo.c */ return 0; }
static renders variable local to the file which is generally a good thing, see for example this Wikipedia entry.
Videos
This is a very broad and open question. During my C learning journey I have been told to avoid using global and static variables. I am still not sure why that is the case.
This is a topic I want to learn more about because it is very blurry to me what exactly is dangerous/undefined behavior when it comes to global and static variables.
From what I understand, marking globals as volatile when dealing with signals can be important to make sure the compiler doesn't interfere with the variable itself, however, I have no idea why that is a thing in the first place and whether it is an absolute truth or not.
Then, there is the whole multithreading thing which I don't even understand right now, so I definitely need to catch up on that, but from what I heard there are some weird things with race conditions and locks to be wary of.
If anyone is well versed about this stuff or has recommended resources on this subject I would be interested to know :)
Whenever the key is changed(by some other threads), my call back notifier is executed in which I update my static global variable with the new key. This key is used everywhere in the program to decrypt some data.
What is trapping you in this kind of thinking is the concept of "the key". It should be "a key".
You think of the key as global so anything that would hold it must be global. Imagine your requirements change and suddenly there are 5 keys running around.
Can't imagine that? Fine, imagine 5 systems, that do nearly the same thing, that must have different keys and all need to be part of your application. How much of your code could be reused?
The key belongs in a context. Within that context there will be only one key. But that doesn't mean there will only ever be one context.
Rather than force everything to find this key by knowing "the one true key" tell them what context they are in by passing them some way to find the key they care about.
That means the key will still only be stored in one place. But now only one place decides where that place is. If you make it global then everything has to know where it is and AGREE on where that is. Ick.
A static global variable is the same global variable, just with a limited compile-time visibility, as @5gon12eder notices above.
Global static state is prone to race conditions. If you have multiple threads accessing this state, you might need locking. If you only have one thread allowed to change the value, you may still have race conditions unless other threads make a copy of the value once and don't depend on repeated reads of the global variable returning the same value.
If you are an expert at writing lock-handling code, you may be fine with that. But likely you won't be asking this question then.
If you have a single-threaded program, these problems mostly go away; the remaining problems may be in unaccounted-for interactions between functions via the global value.
This all is well-known, just summed it up for you.
Is there a difference between a global variable and a static variable in a function? I'm talking in terms of the compiled code that is produced.
one.c
#include <stdio.h>
int test = 1;
void t1() {
printf("%d", test);
test++;
}
int main() {
for(int i = 0; i < 10; i++) {
t1();
}
}two.c
#include <stdio.h>
void t1() {
static int test = 1;
printf("%d", test);
test++;
}
int main() {
for(int i = 0; i < 10; i++) {
t1();
}
}As far as I'm aware, creating static int like this is functionally equivalent of making a global variable. But when I compile them both with "cc -g -o one.o one.c" and then do "objdump -D one.o > one.txt" and diff one.txt with two.txt, there are differences. I can't figure out whether these are superficial differences or whether the compiler is somehow storing int test differently in each case.
In a well-design C program, a file-static variable is similar to a private static member of a class:
It can only be accessed by functions in that file, similar to how a private static member variable can only be accessed by functions in the class in which it is defined.
There is only one copy of the variable.
Its lifetime is the program lifetime.
An extern variable would be a true global variable as in any language that supports them.
A static non-global variable is not as bad as a global; in fact, they are necessary in some cases.
Access is controlled through functions you write. This helps with data integrity including both bounds checking as well as thread-safety. (note: this does not guarantee thread-safety, it is simply one tool to help along the way)
Data is encapsulated: only that file can access it. This is as close as C can get to encapsulation where multiple functions can access a static variable.
Global variables are bad no matter what. Static file variables have the benefits of a private static variable but none of the drawbacks of a global variable.
The only issue is unlike with a true private static variable as in C++, other files can declare an extern variable matching the declaration and you cannot prevent access. In other words, you are relying on the honor system to avoid turning it into a global variable.
Global state, including extern variables and non-const static variables in file scope or in functions can frequently be an easy solution to a given problem, but there are three issues:
staticmakes code untestable, becausestaticvariables tend to be non-replaceable dependencies. Or in more OOP-y words: you aren't following the Dependency Inversion Principle. I came to C and C++ from dynamic languages such as Perl, so my cost model is slanted towards virtual dispatch and function pointers and so on. With current languages, there's some conflict between testability and good architecture, but I think the minor nuisance of making your dependencies explicit and letting them be overridden in tests is noticeably offset by the ease of writing tests, and thus making sure your software is working as expected. Without making your code more dynamic, the only available mechanism to inject dependencies for a test is conditional compilation.Global state makes it difficult to reason about correctness, and that leads to bugs. The more bits and pieces have access to a variable and can modify it, the easier it is to lose track of what's happening. Instead: prefer single assignment of variables! Prefer
constwherever reasonable! Prefer guarding variables through getters and setters where you can introduce correctness checks. As long as the state isstaticand notextern, it is still possible to maintain correctness, but it's always better to assume me-in-a-week won't be as smart as me-right-now. Especially in C++, we can use classes to model various abstractions that make it impossible to misuse something, so try to utilize the type system rather than your intelligence – you have more important stuff to think about.Global state might imply that your functions are not re-entrant, or that they can only be used in one context at a time. Imagine a database driver that could only manage one connection! That's a totally unnecessary restrictions. In reality, the limitations are often subtler, such as a global variable that's used to aggregate results. Instead, make your data flow explicit and pass everything through function parameters. Again, C++ classes can make this more manageable.
Obviously, static const NAMED_CONSTANTS are OK. Using static inside of functions is a lot trickier: while it is useful for lazily initialized constants, it may be fairly untestable. A compromise is to separate calculating the initial value from the static variable, so that both parts can be tested separately.
In small, self-contained programs, all of this won't matter, and you can keep using static state to your hearts delight. But as you pass around 500 LOC or if you are writing a reusable library, you should really start thinking about good architecture and a good interface without unnecessary restrictions.
i has internal linkage so you can't use the name i in other source files (strictly translation units) to refer to the same object.
j has external linkage so you can use j to refer to this object if you declare it extern in another translation unit.
i is not visible outside the module; j is globally accessible.
That is, another module, which is linked to it, can do
extern int j;
and then be able to read and write the value in j. The same other module cannot access i, but could declare its own instance of it, even a global one—which is not visible to the first module.