extern is the storage class specifier that lets one file use a variable or function that is defined in another file. It does not create anything. It only tells the compiler that the name exists somewhere else in the project.
You have already met it in Static Across Files, where file1.c used extern int PrivateData; to reach a global defined in main.c. This note looks at the keyword on its own, first with variables and then with functions.
A global variable in another file
Start with two files. One file defines the variable and gives it a value.
// config.c
int system_clock = 12;The other file wants to use it.
// main.c
#include <stdio.h>
extern int system_clock;
int main() {
printf("System clock: %d\n", system_clock);
return 0;
}Compile both files together and run the program.
gcc main.c config.c -o main
./mainSystem clock: 12The declaration and the definition work as a pair.
config.c main.c
int system_clock = 12; extern int system_clock;
| |
| one storage for the project |
+-------------------------------+
Follow the steps that join the two files.
config.cdefinessystem_clock. The compiler sets aside storage for oneintand puts 12 in it.main.cdeclaressystem_clockwithextern. This tells the compiler the name and type, but no storage is set aside in this file.- Each file is compiled separately.
main.cis allowed to use the name because of the declaration.config.cowns the storage. - The linker joins the two object files. It connects the
externdeclaration inmain.cto the definition inconfig.c. - At run time,
printfreads 12 from that one shared storage.
The variable was defined outside main.c, and extern extended its visibility into main.c.
Important
A definition creates the variable and sets aside memory. An
externdeclaration only says the variable exists somewhere else. The project must still contain exactly one definition.
Why not just write the variable again
Suppose main.c drops the keyword and writes the variable the same way as config.c.
// main.c
#include <stdio.h>
int system_clock;
int main() {
printf("System clock: %d\n", system_clock);
return 0;
}gcc main.c config.c -o main/usr/bin/ld: /tmp/ccwSgqZH.o:(.data+0x0): multiple definition of 'system_clock'
/usr/bin/ld: /tmp/ccH721AE.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit statusWriting int system_clock; outside every function is also a definition. Now both files create a system_clock, and the linker has two candidates. It cannot know which one main means, so it stops.
extern avoids this by declaring the name without creating a second copy.
The opposite mistake is a missing definition. If main.c declares extern int system_clock;, no file defines it, and the program uses it, the linker reports undefined reference to system_clock. Declaration vs Definition shows that error with a full example.
Definition and declaration side by side
| Definition | extern declaration | |
|---|---|---|
| Sets aside memory | Yes | No |
| Can give a starting value | Yes | No, a value here would make it a definition |
| How many in the project | Exactly one | As many as needed in the files that use the name |
| What it tells the compiler | Create this variable here | This variable exists somewhere else |
A function follows the same idea, except there is no memory to set aside for the name. The function body is the definition.
extern with functions
Let one file define a function and another file call it.
// math.c
int add(int a, int b) {
return a + b;
}// main.c
#include <stdio.h>
int add(int a, int b);
int main() {
printf("2 + 3 = %d\n", add(2, 3));
return 0;
}gcc main.c math.c -o main
./main2 + 3 = 5The line int add(int a, int b); is a prototype. It tells the compiler what the function looks like before its body has been seen.
You may also write the keyword in front.
extern int add(int a, int b);This behaves exactly the same. For functions, extern is assumed. A function definition is shared with the whole project by default, and a prototype is treated as an extern declaration even when the word is missing. That is why most C code leaves it out.
Note
externis optional for functions. It is not optional for a global variable when another file wants to use it, because that is the only way to declare the name without also defining it.
When extern matters
extern makes sense only in a project with more than one source file. If everything lives in one file, the variable or function is already visible, so there is nothing to extend. Adding the keyword changes nothing.
The keyword is useful when a name is shared by design, such as a configuration value or a helper function used by several files. It is the opposite of static. A static global variable or static function is private to its file and cannot be reached with extern. See Static Across Files and Static Functions for that side.
Important
externextends visibility to another file. It never creates a new variable or function, and it never makes a private static name public.
The mistakes to watch for
| What you wrote | What goes wrong |
|---|---|
extern int x; and no definition anywhere, but the program uses x | Linker error, undefined reference to x |
int x; in two files that are both compiled | Linker error, multiple definition of x |
extern int x; in one file and int x = 5; in another | Correct, one declaration and one definition |
extern used to reach a static variable or function | Linker error, the static name is private |
The safe pattern is simple. Define the variable once, without extern. In every other file that needs it, write one extern declaration with the same type.
Previous: Static Functions