A real C project is usually more than one source file. One file may hold main, another may hold helper functions, and different people may write different files. In that situation a global variable is visible to every file in the project, which is often more access than you want.
static gives you a way to keep a global variable private to the file that defines it. This note builds a small two-file project to show the problem, the usual extern fix, and why static is sometimes the safer choice.
The project
Make a folder and put two source files in it.
static_1/
├── main.c
└── file1.cStart with an empty function in file1.c.
// file1.c
void file1_myFun1(void) {
}In main.c, create a global variable called PrivateData, print it, and then call the function from the other file.
// main.c
#include <stdio.h>
int PrivateData = 100;
int main() {
printf("Before the call: %d\n", PrivateData);
file1_myFun1();
printf("After the call: %d\n", PrivateData);
return 0;
}The name PrivateData is only a name. Nothing stops another file from changing the variable yet. That is exactly what we are going to test.
First compile: the missing prototype
Compile both files together.
gcc main.c file1.c -o mainmain.c: In function 'main':
main.c:7:9: warning: implicit declaration of function 'file1_myFun1'The compiler is reading main.c on its own. When it reaches the call to file1_myFun1, it has not seen that function anywhere, so it does not know what arguments it takes or what it returns. The line
void file1_myFun1(void);fixes that. It is a prototype, a promise to the compiler that the function is defined in some other file. After adding it, main.c compiles cleanly. The call and the body now agree.
Note
A prototype and a definition are not the same thing. The prototype only describes the function. The body in
file1.cis the definition that actually does the work. Declaration vs Definition explains the difference for variables.
Second compile: the other file cannot see the variable
Now let file1.c change the value. The function tries to assign 900 to PrivateData, and a second printf in main.c will show whether the change reached main.c.
// file1.c
void file1_myFun1(void) {
PrivateData = 900;
}// main.c
#include <stdio.h>
int PrivateData = 100;
void file1_myFun1(void);
int main() {
printf("Before the call: %d\n", PrivateData);
file1_myFun1();
printf("After the call: %d\n", PrivateData);
return 0;
}gcc main.c file1.c -o mainfile1.c: In function 'file1_myFun1':
file1.c:2:2: error: 'PrivateData' undeclared (first use in this function)Each source file is compiled separately. The compiler working on file1.c has never seen the line int PrivateData = 100;, because that line is in main.c. As far as this file knows, the name does not exist.
Telling file1.c that the variable exists
The variable is already defined in main.c. We do not want a second copy, so file1.c needs a declaration, not a definition. The keyword for that is extern.
// file1.c
extern int PrivateData;
void file1_myFun1(void) {
PrivateData = 900;
}extern int PrivateData; says that a variable with this name and type exists somewhere else in the project. No memory is set aside here. The linker connects this name to the one definition in main.c.
Compile and run.
gcc main.c file1.c -o main
./mainBefore the call: 100
After the call: 900Follow what happened, step by step.
- The program starts.
main.chas already set aside storage forPrivateDataand put 100 in it. mainprints 100.maincallsfile1_myFun1.- Inside that function, the
externline does not create anything. It only lets the namePrivateDatarefer to the storage thatmain.ccreated. PrivateData = 900;writes 900 into that shared storage.- The function returns.
mainprints the same storage again and sees 900.
The variable was changed from another file, without main.c ever agreeing to it.
The problem
The name PrivateData was chosen because main.c wants the variable to be private. It expects that no other file will touch it. But a plain global variable is public to the whole project, so any file can declare it with extern and write to it.
That is fine when the variable really is shared. It is risky when only one file should own it. One careless assignment in another file can break the logic in main.c, and the bug will be hard to find because the two lines are in different files.
The static fix
Put static in front of the global variable in main.c.
// main.c
#include <stdio.h>
static int PrivateData = 100;
void file1_myFun1(void);
int main() {
printf("Before the call: %d\n", PrivateData);
file1_myFun1();
printf("After the call: %d\n", PrivateData);
return 0;
}Leave file1.c exactly as it was, with its extern declaration and its assignment. Then compile again.
gcc main.c file1.c -o main/usr/bin/ld: /tmp/ccQ7k3zA.o: in function 'file1_myFun1':
file1.c:(.text+0x0): undefined reference to 'PrivateData'
collect2: error: ld returned 1 exit statusBoth files compiled without complaint. The error comes from the linker, which is the program that joins the compiled pieces together. file1.c still asks for a variable named PrivateData. But the only definition in the project is now a static one inside main.c, and a static definition is not offered to other files. The linker searches, finds nothing it is allowed to use, and stops.
The assignment is now impossible. main.c keeps its private data, and the project does not build until the other file stops reaching for it.
Important
A global variable marked
staticis private to its own source file. Other files cannot reach it, even withextern.
To make the project compile again, remove the extern declaration and the assignment from file1.c and give the function something else to do, or remove the call to it. A static variable cannot be externed.
What changed
Plain global in main.c | Static global in main.c | |
|---|---|---|
Can main.c use the name | Yes | Yes |
Can file1.c use the name | Yes, with extern | No |
| Where the storage lives | One copy for the whole program | One copy, private to main.c |
| Starts at | 0 if not initialized | 0 if not initialized |
The lifetime does not change. In both columns the variable is created before main starts and lives until the program ends. Only the visibility changes. That is the whole point of the keyword here.
Two jobs for one keyword
The word static now has two separate uses, and the position tells you which one you have.
Where you write static | What it does |
|---|---|
| On a variable inside a function | Keeps the value between calls, name still local to the function |
| On a variable outside every function | Keeps the name private to the source file |
| On a function | Keeps the function name private to the source file |
The first row is the one covered in Storage Classes. The second row is the one this note just showed. The third row follows the same idea as the second, but for functions instead of variables. Static Functions covers it.
Note
Two different files may each have their own
static int PrivateData;without a clash. Each one is private to its file, so the linker never has to choose between them. That also means the two variables are separate, and changing one does not change the other.
When to use it
Use static on a global when the variable is only the business of one file. It keeps the project tidy and stops other files from depending on details they should not know about.
Use a plain global, together with an extern declaration in the other files, when the variable really is shared by design. Extern Keyword explains that keyword in detail.
Previous: Storage Classes