A bluffer's guide to the C programming language's hardest working keyword.
Back in the 1970s when the C programming language was invented, keywords were in short supply. Programmers today may find it hard to credit but at the time, with the Cold War at its height, competition for scarce keywords was fierce and often brought the world's superpowers to the brink of open conflict.
Looking back, historians of the period agree that the spectre of all-out nuclear war was never more imminent than in August of 1972 when C inventor Dennis Richie famously smuggled the last unbound keyword out of East Berlin in his beard.1 That keyword was static
.
Having risked nuclear armageddon to secure control of the static
keyword, the inventors of C were determined to extract the greatest possible return on their investment. Ken Thompson would later recall a jubilant Richie exhorting his colleagues at Bell Labs to "work that bitch like a rented mule".2
That's exactly what they did, and the multiple, subtly-overlapping meanings they assigned to their new keyword have been confusing programmers ever since.
Let's put the history lesson behind us for now and focus on the practicalities. The static
keyword acts as a modifier for 'object' (i.e. function and variable) declarations. It's confusing because it has two different effects depending on its context — sometimes it affects the memory model used for object storage and sometimes it affects the visibility (in C terminology, the linkage) of objects.
We're going to need a little background on these topics before going any further.
C allocates storage for objects using one of three memory models: static, dynamic, or automatic.
Static — memory is allocated once when a program starts and persists for the duration of the program's execution. The size and location of a statically allocated block of storage never changes. This is the storage model used for global variables.
Dynamic — memory is dynamically allocated and deallocated on the heap at runtime under the explicit control of the programmer. This is the storage model managed using malloc()
and free()
.
Automatic — memory is automatically allocated on the stack when a function is called and automatically deallocated when that function returns. This is the default storage model for function variables.
Objects in C are visible within one of three scopes: block scope, internal scope, or external scope. The C specification doesn't use the term 'scope', however — instead it refers to these objects as having no linkage, internal linkage, or external linkage.
An object with no linkage is invisible outside of its enclosing block — this is the case for function parameters and function variables.
An object with internal linkage is visible throughout its translation unit, which means its source file after includes and macros have been processed.
An object with external linkage is visible to code throughout an entire executable.
The static
modifier can be applied to:
Let's see how it affects each in turn.
Block-scope variables have no linkage and this property is fixed — the static
keyword has no effect on their visibility.
Block-scope variables use the automatic memory model by default; the static
keyword changes their memory model to static.
File-scope variables have external linkage by default; the static
keyword changes their linkage to internal.
All file-scope variables are allocated using the static memory model; the static
keyword has no memory model implications for them.
Functions have external linkage by default; the static
keyword changes a function's linkage to internal.
Memory for functions is always allocated statically; the static
keyword has no memory model implications for them.
So there we have it. The static
keyword means use static memory allocation, except when it doesn't, when it means give this variable or function internal linkage.
Functions and file-scope variables are statically allocated and externally linked by default; static
leaves them statically allocated and makes them internally linked.
Block-scope variables are automatically allocated and have no linkage by default; static
makes them statically allocated and doesn't affect their linkage.