A function is public by default. Any file in the project can call it, as long as that file has a prototype. Most of the time this is what you want. Sometimes a function is sensitive enough that only the file that owns it should be allowed to call it. static gives you that control for functions too.
This note continues the two-file project from Static Across Files. There the keyword kept a global variable private to its file. Here the same keyword keeps a function private to its file.
The example: a sensitive function
In main.c, write a function that changes the system clock. A real version would call the operating system. Here it only prints the new time, so the example stays short.
// main.c
#include <stdio.h>
void change_system_clock(int system_clock) {
printf("System clock changed to %d\n", system_clock);
}
void file1_myFun1(void);
int main() {
change_system_clock(12);
file1_myFun1();
return 0;
}Changing the system clock is a critical operation. The developer who wrote main.c wants only functions inside main.c to call this function. Other files should not be able to touch it.
Right now nothing enforces that wish. The function is ordinary, so the rest of the project can call it.
Any file can call it
Add a function in file1.c that calls change_system_clock with 0, as if it wanted to freeze the clock.
// file1.c
void change_system_clock(int system_clock);
void file1_myFun1(void) {
change_system_clock(0);
}The prototype on the first line tells the compiler what the function looks like. It does not create the function. The body is still in main.c. Without the prototype, the compiler working on file1.c would not know the name and would warn about an implicit declaration.
Compile both files and run the program.
gcc main.c file1.c -o main
./mainSystem clock changed to 12
System clock changed to 0Follow the calls step by step.
mainstarts.maincallschange_system_clock(12). The function prints 12.maincallsfile1_myFun1, which lives in the other file.file1_myFun1callschange_system_clock(0).- The function prints 0.
The second call came from file1.c, a file that has no business changing the clock. Nothing stopped it.
Note
A function declaration is
externby default. Writingextern void change_system_clock(int system_clock);infile1.cmeans the same as the plain prototype, so the keyword is usually left out.externonly makes sense for a function that is meant to be shared. Extern Keyword covers that case.
The static fix
Put static in front of the function definition in main.c.
// main.c
#include <stdio.h>
static void change_system_clock(int system_clock) {
printf("System clock changed to %d\n", system_clock);
}
void file1_myFun1(void);
int main() {
change_system_clock(12);
file1_myFun1();
return 0;
}Leave file1.c exactly as it was, still calling the function with 0. Compile again.
gcc main.c file1.c -o main/usr/bin/ld: /tmp/ccF2p6TT.o: in function 'file1_myFun1':
file1.c:(.text+0xe): undefined reference to 'change_system_clock'
collect2: error: ld returned 1 exit statusBoth files pass the compiler. The failure happens later, in the linker, which joins the compiled files into one program.
- The compiler turns
main.cinto an object file. It recordschange_system_clockas a private name that other files may not use. - The compiler turns
file1.cinto another object file. That file asks for a function namedchange_system_clockfrom somewhere outside itself. - The linker looks through all the object files for a shared function with that name.
- The only one it finds is private to
main.c, so it refuses to use it. - The link fails with
undefined reference.
The function is still callable inside main.c. It is simply invisible to every other file. This is why a static function is also called a private function.
Important
A function marked
staticcan be called only by other functions in the same source file. Other files cannot call it, even with anexterndeclaration or a matching prototype.
What changed
Plain function in main.c | Static function in main.c | |
|---|---|---|
| Who can call it | Any file with a prototype | Only functions in main.c |
| What another file needs | A prototype, with extern optional | Nothing helps, it cannot call it |
| Where the body must be | Any file in the project | The same file as the static definition |
| Name seen by the linker | Yes, as a shared name | No, it stays private |
For functions, static changes visibility, not lifetime. The machine code is part of the program until the program ends either way. The keyword only decides which file is allowed to use the name.
The rule that catches people
A static function must be defined in the file that wants to call it. You cannot define it in file1.c and call it from main.c after marking it static. The moment you mark it static, it belongs to its own file.
If you need a prototype before the definition in the same file, put static on the prototype too.
static void change_system_clock(int system_clock);
static void change_system_clock(int system_clock) {
printf("System clock changed to %d\n", system_clock);
}Writing a plain prototype first and adding static later is a conflict. The compiler complains that a static declaration follows a non-static declaration.
Note
Two files may each define their own static function with the same name. Each one is private to its file, so the linker never has to choose between them. This also lets two developers use the same helper name without stepping on each other.
Where this fits with the other uses
The word static now has three jobs. 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 variable name private to the source file |
| On a function | Keeps the function name private to the source file |
The first row is covered in Storage Classes. The second row is covered in Static Across Files. This note covered the third row.
When to use it
Use static on a function when it is an internal helper that only its own file needs, or when calling it from outside would be dangerous, as with the system clock example. It keeps the project’s public surface small and stops other files from depending on details they should not know about.
Use a plain function when other files really are meant to call it. Then give them a prototype, the way file1.c did in this note, and leave the definition public.
Previous: Static Across Files