Skip to content

Scopes and linkage

7.1 — Compound Statements (Blocks)

A compound statement (also called a block) is a group of zero or more statements treated by the compiler as a single statement.

  • Syntax: Enclosed in curly braces { }.

  • Nesting: Blocks can be nested inside other blocks.

  • Scope: Variables defined inside a block are local to that block and are destroyed when the block ends.


7.2 — User-Defined Namespaces

Namespaces help prevent naming collisions by allowing you to group identifiers into a named scope.

  • Scope Resolution Operator (::): Used to access an identifier inside a namespace (e.g., NamespaceName::identifier).

  • Nesting: You can nest namespaces inside each other.

  • Namespace Aliases: Allow you to create a shorter name for a long or nested namespace (e.g., namespace fb = foo::bar;).


7.3 — Local Variables

Local variables are defined inside a function or a block.

  • Scope: Local scope (only accessible within the block they are defined).

  • Duration (Lifetime): Automatic storage duration (created at definition, destroyed at the end of the block).

  • Linkage: No linkage (cannot be referred to by other files or even other functions).


7.4 & 7.5 — Global Variables and Shadowing

Global variables are defined outside of any function.

  • Scope: File scope (accessible from the point of definition to the end of the file).

  • Duration: Static duration (created when the program starts, destroyed when it ends).

  • Variable Shadowing: Occurs when a local variable has the same name as a global variable. The local variable "hides" the global one within that local scope. You can still access the global version using the global scope resolution operator (e.g., ::value).


7.6 & 7.7 — Internal and External Linkage

Linkage determines whether multiple declarations of an identifier refer to the same object.

  • Internal Linkage: The identifier can be used anywhere within the file it is defined, but it is invisible to other files.

    • Keyword: static (for non-const globals).

    • Note: const and constexpr globals have internal linkage by default.

  • External Linkage: The identifier can be seen and used by other files in the project.

    • Keyword: extern.

    • Forward Declaration: To use an external variable in another file, you must provide a forward declaration using extern without an initializer.


7.8 — Why (Non-Const) Global Variables are Evil

While tempting, non-const global variables are generally considered bad practice:

  1. State Unpredictability: Any function can change the variable, making it hard to track where a bug originated.

  2. Coupling: Functions become dependent on the global state, making them harder to move to other projects or test in isolation.

  3. Concurrency: They make multi-threaded programming much more difficult.


7.9 & 7.10 — Inline Functions and Variables

The inline keyword has evolved from a performance hint to a tool for managing definitions across multiple files.

  • Inline Functions/Variables: Can be defined in multiple files (usually via a header) without violating the One Definition Rule (ODR), provided the definitions are identical.

  • Sharing Constants: The modern way to share global constants is to put inline constexpr variables in a header file. This gives you the best of both worlds: a single source of truth and no "duplicate definition" errors.


7.11 — Static Local Variables

Using the static keyword on a local variable changes its duration but not its scope.

  • Behavior: The variable is initialized only the first time the function is called. It "remembers" its value between function calls.

  • Lifetime: It lasts for the entire duration of the program, even though it can only be seen inside the function.


7.12 — Scope, Duration, and Linkage Summary

Property Local Variable Global Variable Static Local
Scope Block Scope File Scope Block Scope
Duration Automatic Static Static
Linkage None Internal or External None

7.13 — Using Declarations and Directives

  • Using Declaration: Brings a specific name into the current scope (e.g., using std::cout;). Safest way to avoid prefixing.

  • Using Directive: Brings the entire namespace into the current scope (e.g., using namespace std;).

    • Warning: Avoid using namespace std; in the global scope or in header files, as it significantly increases the risk of naming collisions.

7.14 — Unnamed and Inline Namespaces

  • Unnamed Namespaces: All identifiers inside are treated as having internal linkage (effectively replaced the static keyword for functions/globals).

  • Inline Namespaces: Often used for versioning. Identifiers in an inline namespace are treated as if they are part of the parent namespace, allowing for seamless library updates.