extern Keyword in C – Declaration, Definition, and Multi-File Programs

The extern keyword in C declares that a variable or function exists — but is defined somewhere else. It tells the compiler “trust me, this symbol is defined in another translation unit; the linker will resolve it.” Understanding extern is essential for any multi-file C program, and confusing declaration with definition is one of the most common C beginner mistakes.

Declaration vs Definition

The distinction is fundamental:

Declaration Definition
What it does Tells the compiler a symbol exists and its type Allocates storage; creates the symbol
How many times As many times as needed Exactly once per program
Storage allocated No Yes
Example extern int count; int count = 0;

A variable declaration with an initialiser is always a definition, even if prefixed with extern:

extern int x;      /* declaration — no storage allocated */
extern int x = 5;  /* DEFINITION despite extern — initialiser forces it */
int x = 5;         /* also a definition */

How extern Works in a Multi-File Program

Here is the canonical two-file example:

/* ── file1.c ── defines the variable ─────────────────────── */
#include <stdio.h>

int counter = 0;      /* definition: storage allocated here */

void increment(void)
{
    counter++;
}
/* ── file2.c ── uses the variable from file1.c ───────────── */
#include <stdio.h>

extern int counter;   /* declaration: no storage; tells compiler type */
void increment(void); /* function declaration */

int main(void)
{
    printf("counter = %d\n", counter);   /* 0 */
    increment();
    increment();
    printf("counter = %d\n", counter);   /* 2 */
    return 0;
}

How to Compile

gcc -ansi -Wall -Wextra -o program file1.c file2.c
./program

Sample Output

counter = 0
counter = 2

The Right Way: extern in Header Files

Repeating extern int counter; in every file that uses it is error-prone. The standard practice is to declare the variable in a header file and include it everywhere:

/* ── counter.h ─────────────────────────────────────────── */
#ifndef COUNTER_H
#define COUNTER_H

extern int counter;   /* declaration — include anywhere */
void increment(void);

#endif
/* ── counter.c ─────────────────────────────────────────── */
#include "counter.h"

int counter = 0;      /* definition — exactly here, exactly once */

void increment(void)
{
    counter++;
}
/* ── main.c ─────────────────────────────────────────────── */
#include <stdio.h>
#include "counter.h"   /* gets the extern declaration */

int main(void)
{
    printf("counter = %d\n", counter);
    increment();
    increment();
    increment();
    printf("counter = %d\n", counter);
    return 0;
}
gcc -ansi -Wall -Wextra -o program counter.c main.c
./program
counter = 0
counter = 3

extern for Functions

Functions have external linkage by default in C — you don’t need extern for function declarations. These two are identical:

extern void increment(void);   /* explicit extern */
void increment(void);          /* implicit extern — preferred */

Both are declarations (no function body). Including either in a header file works correctly. The explicit extern on a function is legal but redundant.

extern vs static — Linkage at a Glance

Declaration Linkage Visible to other files? Use case
int x = 0; (file scope) External Yes Shared global variable
extern int x; External (declaration only) Yes Use a global from another file
static int x = 0; (file scope) Internal No — file-private Module-internal state
static int x; (inside function) No linkage No Persistent local state

Prefer static over global variables whenever possible. If a variable only needs to be accessed within one file, mark it static at file scope. This prevents other translation units from accidentally depending on it, reduces coupling, and enables better compiler optimisations.

Common Mistakes

  • Defining the variable in the header: if you write int counter = 0; (without extern) in a header that is included by multiple files, you get a “multiple definition” linker error — the storage is allocated in every translation unit that includes the header.
  • extern int x = 5; is a definition: the initialiser forces storage allocation. The extern qualifier is ignored for initialised declarations.
  • Missing the definition entirely: if you declare extern int counter; but never define int counter; anywhere, the linker reports “undefined reference to counter”.
  • Type mismatch: declaring extern int x; but defining long x; in another file compiles without error but causes silent data corruption at runtime. The header file pattern prevents this — both files include the same declaration.

extern in C++ Programs (extern "C")

When calling C code from C++, name mangling causes linker errors — C++ encodes argument types in function names, but C-compiled code uses plain names. The fix is:

/* In a C++ file, or a header that C++ code includes: */
#ifdef __cplusplus
extern "C" {
#endif

void increment(void);   /* C function — no name mangling */
extern int counter;

#ifdef __cplusplus
}
#endif

This is purely a C++ concern — it has no effect when the header is included from a C file.

What This Teaches

  • Declaration vs definition: the most important distinction in C’s linkage model — each symbol can be declared many times but defined exactly once
  • Header file discipline: extern declarations belong in headers; definitions belong in exactly one .c file — the header pattern enforces this mechanically
  • Prefer static over global: restricting a symbol’s visibility to the file that owns it makes the codebase easier to reason about and refactor

Related Programs


As an Amazon Associate we earn from qualifying purchases.

Recommended Book

Linkage, storage classes, and the translation unit model are covered in sections 4.3–4.6 of The C Programming Language by Kernighan & Ritchie — the definitive reference for understanding how C programs are structured across multiple files. Also on Amazon.com.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>