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
./main
System clock changed to 12
System clock changed to 0

Follow the calls step by step.

  1. main starts.
  2. main calls change_system_clock(12). The function prints 12.
  3. main calls file1_myFun1, which lives in the other file.
  4. file1_myFun1 calls change_system_clock(0).
  5. 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 extern by default. Writing extern void change_system_clock(int system_clock); in file1.c means the same as the plain prototype, so the keyword is usually left out. extern only 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 status

Both files pass the compiler. The failure happens later, in the linker, which joins the compiled files into one program.

  1. The compiler turns main.c into an object file. It records change_system_clock as a private name that other files may not use.
  2. The compiler turns file1.c into another object file. That file asks for a function named change_system_clock from somewhere outside itself.
  3. The linker looks through all the object files for a shared function with that name.
  4. The only one it finds is private to main.c, so it refuses to use it.
  5. 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 static can be called only by other functions in the same source file. Other files cannot call it, even with an extern declaration or a matching prototype.

What changed

Plain function in main.cStatic function in main.c
Who can call itAny file with a prototypeOnly functions in main.c
What another file needsA prototype, with extern optionalNothing helps, it cannot call it
Where the body must beAny file in the projectThe same file as the static definition
Name seen by the linkerYes, as a shared nameNo, 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 staticWhat it does
On a variable inside a functionKeeps the value between calls, name still local to the function
On a variable outside every functionKeeps the variable name private to the source file
On a functionKeeps 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