Question

How to Use extern to Share Variables Between Source Files in C

ccppglobal-variablesextern

Question

I want to understand how the extern keyword is used in C to share variables between source files.

I know that global variables sometimes appear with the extern keyword, but I am not sure what an extern variable actually is. Specifically:

  • What does extern mean for a variable?
  • What does the declaration look like?
  • What scope does such a variable have?
  • How does sharing a variable across multiple .c files work in practice?
  • In which file should extern be used, and where should the variable actually be created?

For example, I am trying to understand the pattern behind code like this:

/* file1.c */
int counter = 0;

/* file2.c */
extern int counter;

How does this work precisely in C?

Short Answer

By the end of this page, you will understand the difference between declaring and defining a global variable in C, what extern means, how scope and linkage affect shared variables, and how to correctly share one variable across multiple source files without causing linker errors.

Concept

In C, extern is mainly used to say:

"This variable exists somewhere else. I want to use it here, but I am not creating storage for it in this file."

That idea is the key to understanding extern.

Declaration vs definition

A global variable can appear in two important ways:

  • Definition: actually creates the variable and allocates storage for it.
  • Declaration: tells the compiler the variable exists and what its type is.

Example:

int counter = 0;      // definition
extern int counter;   // declaration

The definition creates one real counter variable in the program. The extern declaration does not create a second variable. It only allows another source file to refer to the existing one.

Why this matters

C programs are often split into multiple .c files. Each source file is compiled separately, so the compiler needs to know the types of names used in that file. If one file wants to use a global variable defined in another file, it needs a declaration. That is what extern is for.

Scope vs linkage

Beginners often confuse scope and linkage.

  • Scope answers: where in the code can this name be used?
  • Linkage answers: does this name refer to the same object across different files?

A file-scope variable like this:

int counter = 0;

has:

  • file scope: from its declaration to the end of the file
  • external linkage by default: other files can refer to the same variable using extern

A declaration like this:

extern int counter;

also has file scope if written outside a function, but it does not define storage.

The common pattern

Usually you do this:

In a header file

/* globals.h */
extern int counter;

In exactly one source file

/* globals.c */
int counter = 0;

In any file that uses it

/* main.c */
#include "globals.h"

int main(void) {
    counter++;
    return 0;
}

This works because:

  • the header gives every file the declaration
  • one .c file gives the program the actual definition
  • the linker connects all references to the same variable

Important rule

If you define the variable in more than one source file, you usually get a multiple definition linker error.

If you declare it with extern everywhere but never define it anywhere, you usually get an undefined reference linker error.

So the rule is:

  • declare with extern in headers or other files
  • define once in exactly one .c file

Mental Model

Think of a shared global variable like a company storage locker.

  • The definition is the actual locker built in one location.
  • An extern declaration is a note telling people: "The locker exists in building A; use that one."
  • If every building creates its own locker with the same name, there is confusion.
  • If everyone only has notes but no locker was ever built, nothing can be stored.

So:

  • one real locker = one definition
  • many references to that locker = extern declarations

This is why extern is about referring to existing storage, not creating new storage.

Take Quiz

Syntax and Examples

Core syntax

Define a global variable

int counter = 0;

This creates the variable.

Declare a global variable from another file

extern int counter;

This says the variable exists somewhere else.

Basic multi-file example

globals.h

#ifndef GLOBALS_H
#define GLOBALS_H

extern int counter;

#endif

globals.c

#include "globals.h"

int counter = 0;

main.c

#include <stdio.h>
#include "globals.h"

int main(void) {
    printf("Before: %d\n", counter);
    counter += 5;
    printf("After: %d\n", counter);
    return 0;
}

What this does

  • globals.h tells other files that counter exists.
  • globals.c creates the actual variable.
  • main.c uses that variable.

All files refer to the same counter.

Inside a function

You can also write:

void print_counter(void) {
    extern int counter;
    printf("%d\n", counter);
}

This is valid, but less common. In real code, developers usually put the declaration in a header and include it where needed.

extern with functions

Functions also have external linkage by default, so this is similar:

int add(int a, int b);

You could write:

extern int add(int a, int b);

but for functions, extern is usually omitted because it is implied.

Step by Step Execution

Consider these files.

globals.h

#ifndef GLOBALS_H
#define GLOBALS_H

extern int counter;

#endif

globals.c

#include "globals.h"

int counter = 10;

main.c

#include <stdio.h>
#include "globals.h"

int main(void) {
    printf("%d\n", counter);
    counter++;
    printf("%d\n", counter);
    return 0;
}

Step-by-step

1. globals.h is included in main.c

The compiler sees:

extern int counter;

So it learns:

  • there is an int named counter
  • this file may use it
  • storage is not created here

2. globals.c is compiled

The compiler sees:

int counter = 10;

This creates the real global variable.

3. main.c is compiled

main.c uses counter in printf and counter++. That is allowed because the compiler already saw its declaration from the header.

4. Linking happens

The linker combines the compiled object files.

  • main.c refers to a variable named counter
  • globals.c provides the definition of counter

The linker connects them.

5. Program runs

Initial value:

counter == 10

Then this line runs:

counter++;

Now:

counter == 11

Output:

10
11

Key takeaway

Compilation checks types and names within each file. Linking connects declarations to definitions across files.

Real World Use Cases

When shared globals are used

Although global variables should be used carefully, they do appear in real C programs.

Configuration flags

extern int debug_enabled;

Used by multiple source files to enable extra logging.

Program state counters

extern unsigned long request_count;

Useful in small tools or embedded systems to count events.

Hardware register mappings in embedded C

A shared global may represent device state or a system-wide handle used across modules.

Shared error/status values in legacy code

Older codebases sometimes expose shared status variables accessible from several files.

Better alternatives in many cases

In modern C code, developers often prefer:

  • passing values through function parameters
  • keeping state inside a struct
  • limiting visibility with static
  • exposing accessor functions instead of raw globals

These approaches reduce coupling and make code easier to test.

Take Quiz

Real Codebase Usage

In real projects, extern is usually part of a small, repeatable pattern.

Common pattern: declaration in header, definition in source

app_state.h

#ifndef APP_STATE_H
#define APP_STATE_H

extern int app_mode;

#endif

app_state.c

#include "app_state.h"

int app_mode = 1;

This is the standard way to expose one global object to multiple files.

Common pattern: hide most globals with static

Developers often avoid exposing variables unless necessary.

static int internal_cache_size = 128;

This variable can only be used inside its own .c file. That is often safer.

Access through functions

Instead of exposing a writable global directly, a codebase may do this:

/* config.h */
int get_log_level(void);
void set_log_level(int level);
/* config.c */
static int log_level = 0;

int get_log_level(void) {
    return log_level;
}

void set_log_level(int level) {
    log_level = level;
}

This gives more control and allows validation.

Validation and guard clauses

When globals affect program behavior, developers often combine them with checks:

extern int max_connections;

int open_connection(void) {
    if (max_connections <= 0) {
        return -1;
    }

    return 0;
}

Why teams are cautious

Shared global state can make code harder to reason about because any file may change it. extern is useful, but many real codebases keep its usage limited.

Common Mistakes

1. Defining the variable in a header

This is a very common mistake.

Broken code

/* globals.h */
int counter = 0;

If several .c files include this header, each file gets its own definition, causing linker errors.

Correct version

/* globals.h */
extern int counter;
/* globals.c */
int counter = 0;

2. Using extern but never defining the variable

Broken code

/* globals.h */
extern int counter;

If no source file contains:

int counter;

then the linker cannot find the real variable.

3. Confusing scope with linkage

Beginners may think extern changes scope everywhere automatically. It does not.

void f(void) {
    extern int counter;
    counter++;
}

Here, the name counter is visible only inside f, but it still refers to a variable defined elsewhere.

4. Mixing static and extern

Broken idea

/* file1.c */
static int counter = 0;

/* file2.c */
extern int counter;

This does not work for sharing.

Why?

  • static at file scope gives internal linkage
  • the name is private to file1.c
  • file2.c cannot access it

5. Assuming extern creates storage

This is false for normal variable declarations.

extern int counter;

This declares only. It does not allocate storage.

6. Forgetting to include the shared header

If one file manually writes a different declaration, types can drift.

Risky

extern long counter;

while the real definition is:

int counter = 0;

Type mismatches across files can cause undefined behavior or linker/compiler problems. Use one shared header to avoid this.

Comparisons

extern declaration vs definition

FormExampleCreates storage?Typical use
Definitionint counter = 0;YesCreate the variable once
Declaration with externextern int counter;NoRefer to variable defined elsewhere

External linkage vs internal linkage

Keyword/formExampleVisible from other files?Notes
Default global definitionint counter = 0;YesExternal linkage by default
File-private globalstatic int counter = 0;NoInternal linkage
Reference to external variableextern int counter;Refers to external nameDoes not define storage

extern vs static

Conceptexternstatic at file scope
Main purposeRefer to a variable defined elsewhereRestrict visibility to one source file
Storage created?No, not by itselfYes, if it is a definition
Cross-file accessYesNo

Global variable vs function parameter

ApproachProsCons
Shared global with externEasy to access from many filesTight coupling, harder to test
Pass as parameterClear data flow, easier to testMore code to pass state around
Store in a structGroups related state cleanlyRequires slightly more design
Take Quiz

Cheat Sheet

Quick rules

  • extern usually means: this variable is defined somewhere else
  • Use extern for declarations, not for creating the variable
  • Define the variable once in one .c file
  • Put the extern declaration in a header if multiple files need it
  • Include that header wherever the variable is used

Common pattern

/* globals.h */
extern int counter;
/* globals.c */
int counter = 0;
/* main.c */
#include "globals.h"
counter++;

Remember

  • int counter = 0; → definition
  • extern int counter; → declaration
  • static int counter = 0; → private to that source file

Linkage summary

  • file-scope int counter; → usually external linkage
  • file-scope static int counter; → internal linkage
  • file-scope extern int counter; → declaration of external name

Common errors

Multiple definition

Caused by defining the same global in more than one .c file, or in a header included by multiple files.

Undefined reference

Caused by declaring with extern but never providing one real definition.

Best practice

  • Prefer fewer globals
  • If a global must be shared, expose it through one header and define it once
  • Consider static or accessor functions when possible

FAQ

What does extern mean in C?

It means the variable or function is declared here but defined somewhere else, usually in another source file.

Does extern create a variable?

No. A declaration like extern int x; does not create storage for x. It only tells the compiler that x exists.

Where should I put extern declarations?

Usually in a header file, so every source file that needs the variable can include the same declaration.

Where should I define the actual global variable?

In exactly one .c file.

What is the difference between extern int x; and int x;?

extern int x; is a declaration only. int x; at file scope is typically a definition.

Can I use extern inside a function?

Yes. It declares that the name refers to an external variable, but this is less common than putting the declaration in a header.

Can extern access a static variable from another file?

No. A static file-scope variable has internal linkage and is private to its own source file.

Is using global variables with extern good practice?

Sometimes it is acceptable, especially in small or embedded programs, but overusing globals can make code harder to maintain and test.

Take Quiz

Mini Project

Description

Build a small multi-file C program that keeps track of how many tasks have been completed. The counter should be shared across source files using extern. This demonstrates the correct pattern for declaring a shared global in a header and defining it in exactly one .c file.

Goal

Create a program where multiple source files read and update the same global counter variable.

Requirements

  • Create a header file that declares a shared variable with extern.
  • Define the shared variable in exactly one source file.
  • Use one source file to increase the counter.
  • Use another source file to print the counter.
  • Confirm that both files access the same variable.
Take Quiz

Keep learning

Related questions

View more