Placement Prep

Internal and External Linkage in C: With Code Examples

The static keyword restricts a C identifier to one translation unit; extern exposes it across files. Learn the rules, see the code, and know what interviewers test.

By FACE Prep Team 6 min read
c-programming linkage static-keyword extern-keyword placement-prep technical-interviews

Linkage in C governs whether the linker can see a symbol outside the file where it was declared.

Two patterns cause the most common linker errors in multi-file C programs: a symbol that should stay private gets exported by default, or a symbol needed across files never gets the extern declaration the linker expects. Both trace to the same conceptual gap.

What Linkage Actually Controls

Linkage is not the same as scope. Scope is a compile-time concept that determines where in the source text a name is visible to the compiler. Linkage is a link-time concept that determines which symbols the linker exports from one translation unit and which it keeps private.

A translation unit is one .c source file after its #include directives are expanded. The compiler processes each translation unit separately and produces an object file. The linker then reads all the object files and resolves cross-file symbol references.

C has three linkage categories, defined in the C storage-class specifiers specification on cppreference:

  • No linkage: local variables and function parameters. The linker ignores them entirely.
  • Internal linkage: symbols restricted to one translation unit. The linker does not export them.
  • External linkage: symbols visible to all translation units. The linker exports and resolves them across files.

Understanding this distinction prevents a class of bugs that scope rules alone cannot explain. Two global identifiers can have the same name in different files without conflict if both are static. Two files can share a single global variable if one defines it and the other declares extern. The compiler enforces scope; the linker enforces linkage. When a project grows beyond a single .c file, every global symbol is either deliberately shared or deliberately private; the programmer, not the compiler, has to make that call.

Internal Linkage: The static Keyword at File Scope

Apply static to a global variable or function (outside any function body) and the compiler restricts that symbol to the current translation unit. The linker never sees it. No other .c file can reference it.

/* file1.c */
#include <stdio.h>

static int count = 0;           /* internal linkage */

static void increment(void) {   /* internal linkage */
    count++;
    printf("count = %d\n", count);
}

Both count and increment are invisible outside file1.c. A call to increment from file2.c produces “undefined reference to increment” at link time because the symbol was never exported.

Why file-scope static matters

Large C codebases use file-scope static to enforce module boundaries. A sort routine’s helper comparator and a parser’s token buffer are implementation details. Marking them static prevents name collisions with identically named symbols in other files and makes each module’s public interface explicit without requiring a private keyword.

The convention in well-structured C projects is to expose only the public symbols in a header file and keep every internal helper static in the implementation file. The linker enforces the rule. Removing static from a helper by accident produces a duplicate-symbol warning when a second file defines something with the same name. That error is easier to fix than a runtime bug caused by two files silently sharing state they should not share.

External Linkage: Globals Are Exported by Default

A global variable or function declared without static has external linkage by default. The linker exports it, and any other translation unit can reference it by using extern.

/* file1.c */
#include <stdio.h>

int count = 10;          /* external linkage: exported to the linker */

void showCount(void) {   /* external linkage */
    printf("count = %d\n", count);
}
/* file2.c */
#include <stdio.h>

extern int count;            /* declaration: symbol defined in another file */
extern void showCount(void); /* declaration */

int main(void) {
    showCount();
    return 0;
}

The extern keyword is a declaration, not a definition. It tells the compiler that count and showCount exist somewhere in the program; the linker finds the definitions in file1.c and connects them. The full grammar is covered on the cppreference extern keyword page.

The one-definition rule

A symbol with external linkage can be declared many times (via extern) but defined exactly once. Two definitions of the same externally linked symbol produce a “multiple definition” linker error. This is a common mistake when a definition is copied into a header file instead of staying in a .c file.

No Linkage: Local Variables

Local variables declared inside a function have no linkage. They exist on the stack for the duration of their scope, and the linker has no concept of them.

Adding static to a local variable changes its storage duration (the variable survives across function calls, stored in the data segment rather than the stack) but does not change its linkage. It still has no linkage.

void counter(void) {
    static int calls = 0;  /* no linkage; storage duration: program lifetime */
    calls++;
    printf("calls = %d\n", calls);
}

calls persists between invocations of counter. It is not accessible from anywhere outside the function. The linker does not see it. This is one of the most reliably confusing points in C technical rounds: students who know static means “hidden from other files” apply that logic to local variables and arrive at the wrong answer. The static-local pattern is about persistence, not visibility.

Comparing the Three Types

PropertyNo LinkageInternal LinkageExternal Linkage
Where declaredInside a functionFile scope + staticFile scope, no static
Linker visibilityNoneNone (private)Exported
Accessible from other filesNoNoYes (via extern)
static requiredNoYesNo
Common use caseLocal computationModule-private helpersShared globals, public API

The practical decision rule: if nothing outside the current file needs a global symbol, mark it static. If another file does need it, define it once in a .c file and expose it via extern in a shared header. Applying this rule consistently means the table above becomes something you use to debug, not something you need to memorise.

What Interviewers Actually Test

Linkage questions appear in technical screening rounds at service-tier companies and product-tier companies alike. Four patterns come up most often.

The static overloading question

/* file1.c */
static int x = 5;

/* file2.c */
static int x = 10;
  • Q: What is the value of x in each file?
  • A: Two independent variables. file1.c holds 5; file2.c holds 10. No conflict. The linker never sees either one.

The missing definition

/* file2.c */
extern int result;

int main(void) {
    return result;
}
  • Q: What error appears if no file defines int result?
  • A: “undefined reference to result” at link time. The extern declaration told the compiler to trust the definition exists. The linker searched every object file and found nothing.

The static-local trap

int add(int a, int b) {
    static int calls = 0;
    calls++;
    return a + b;
}
  • Q: Does calls have internal linkage?
  • A: No. calls has no linkage. static here changes storage duration only; the variable is still local to the function. The linker does not see it.

The header-definition trap

/* utils.h */
int g_error_code = 0;  /* definition in a header */

When utils.h is included in three .c files:

  • Q: What does the linker report?
  • A: Three object files each define g_error_code. The linker finds three definitions of the same externally linked symbol and errors with “multiple definition of g_error_code”. The correct approach is to write extern int g_error_code; in the header and add int g_error_code = 0; in exactly one .c file.

Practice the full range of scope and storage-class patterns in C coding questions. Multi-function programs such as the Pascal’s triangle program in C are useful for applying file-scope static to helper functions and confirming the helpers stay invisible across files.

From Theory to Working Code

Technical screening rounds test whether you know the rules. Product-company interviews test something sharper: given a “multiple definition” linker error during a code review, can you trace it to the missing static in sixty seconds.

That diagnostic move (recognising that the linker sees both definitions because neither is static) uses the same mental model as effective LLM debugging: recognising that a model outputs a wrong answer because the relevant fact was absent from its context window. Both are about knowing precisely what the system can and cannot see.

TinkerLLM at ₹299 builds that reasoning for LLMs through short experiments, not a list of rules to memorise. If you are past the C fundamentals and want the additional layer that product companies increasingly screen for, it is a low-cost way to find out whether applied AI is worth the deeper investment.

Primary sources

Frequently asked questions

Does the static keyword inside a function create internal linkage?

No. static inside a function changes storage duration only; the variable persists between calls but still has no linkage. Only static at file scope creates internal linkage.

Can two .c files each define a static variable with the same name?

Yes, that is the point. static int count in file1.c and static int count in file2.c are entirely separate variables. The linker never sees either one.

What does 'undefined reference' have to do with linkage?

When you declare extern int x in file2.c but never define int x anywhere, the linker cannot resolve the symbol. 'Undefined reference to x' is the result. Linkage declared, definition absent.

Is extern necessary when calling a function from another .c file?

Not strictly. A plain function prototype in a header file is implicitly extern. But explicit extern communicates intent and avoids accidental redefinition issues in large codebases.

What is a translation unit in C?

A translation unit is one .c source file after all its #include directives are expanded. Linkage rules operate at translation-unit boundaries: internal means visible within one unit, external means visible across all of them.

Does const at file scope in C give internal linkage?

No, unlike C++, a const variable at file scope in C has external linkage by default. Add static explicitly to restrict it: static const int MAX = 100;

Build AI projects

A self-paced playground for building with LLMs.

TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.

Try TinkerLLM (₹299 launch)
Free AI Roadmap PDF