C++

Compilation & Linking

11 question(s)

What are the stages of building a C++ program?

Beginner
Building involves: preprocessing (handling #include/#define to produce a translation unit), compilation (translating each translation unit to an object file, checking syntax and types), and linking (combining object files and libraries, resolving symbol references, into an executable or library). Understanding the stages helps diagnose where an error (preprocessor, compiler, or linker) occurs.
g++ -E  file.cpp   # preprocess
g++ -c  file.cpp   # compile to file.o
g++ file.o -o app  # link
Real-world example A 'undefined reference' error is a linker error, not a compiler error—knowing the stages pinpoints the fix.

Common follow-ups: What are the three main stages? | Which stage resolves symbols?

Preprocessor & Macros Compilation & Linking Compilation & Linking

What is a translation unit?

Beginner
A translation unit is a single source file after preprocessing—the .cpp file with all its #included headers textually expanded. The compiler processes one translation unit at a time into an object file. Concepts like internal linkage and the one-definition rule are defined in terms of translation units.
Real-world example Each .cpp plus its expanded headers is one translation unit compiled independently into a .o file.

Common follow-ups: What does the compiler do per translation unit? | How do headers relate to it?

Preprocessor & Macros Compilation & Linking Compilation & Linking

What is the difference between declaration and definition?

Intermediate
A declaration introduces a name and its type (promising it exists somewhere); a definition also provides the implementation/storage. You can declare something many times but define it only once (per the ODR). Header files typically contain declarations; source files contain definitions. Using an undeclared name is a compile error; a missing definition is a link error.
extern int x;      // declaration
int x = 5;         // definition
void f();          // declaration
void f(){}         // definition
Real-world example A function declared in a header but never defined causes an 'undefined reference' at link time.

Common follow-ups: How many times can you define something? | Where do declarations usually go?

Compilation & Linking Namespaces Compilation & Linking

What is the One Definition Rule (ODR)?

Intermediate
The ODR states that every entity (variable, function, class, template) must have exactly one definition across the whole program (with specific exceptions: inline functions/variables and templates may be defined identically in multiple translation units). Violating the ODR—e.g., two different definitions of the same function—is undefined behavior, often a link error or subtle bug.
Real-world example Defining a non-inline function in a header included by two files causes an ODR-violation multiple-definition link error.

Common follow-ups: What are the ODR exceptions? | What happens if you violate it?

Compilation & Linking Templates Compilation & Linking

What is internal versus external linkage?

Advanced
External linkage means a name is visible across translation units (can be referenced from other files)—the default for non-const globals and functions. Internal linkage confines a name to its translation unit—given by static at namespace scope or an anonymous namespace, or by const/constexpr namespace-scope variables. Linkage controls symbol visibility and helps avoid multiple-definition clashes.
static int helper();     // internal linkage
int globalCounter;       // external linkage
Real-world example Marking a file-local helper static (internal linkage) prevents a symbol clash with a same-named function elsewhere.

Common follow-ups: What gives internal linkage? | What is the default for functions?

Namespaces Compilation & Linking Compilation & Linking

What causes an 'undefined reference' (unresolved symbol) linker error?

Beginner
It means a symbol was declared and used but the linker couldn't find its definition: a missing source file/object, a library not linked, a function declared but never defined, a signature mismatch (name mangling differs), or forgetting extern "C" for C functions. The fix is to provide/link the definition or correct the declaration.
// declared void f(); used f(); but f never defined -> undefined reference
Real-world example Forgetting to link the math library or a .cpp file yields an 'undefined reference' at link time.

Common follow-ups: What are common causes? | Is it a compiler or linker error?

Compilation & Linking Namespaces Compilation & Linking

What is name mangling?

Intermediate
Name mangling is how the C++ compiler encodes a function's name together with its namespace, class, and parameter types into a unique linker symbol—necessary because C++ supports overloading (same name, different parameters). It's why linker errors show decorated names and why calling C code needs extern "C" (which disables mangling for C-compatible names).
// void f(int) and void f(double) get different mangled symbols
Real-world example A link error shows a mangled symbol; demangling it reveals the exact overloaded function that's missing.

Common follow-ups: Why is mangling needed? | How does extern "C" relate to it?

Compilation & Linking Namespaces Compilation & Linking

What is the difference between static and dynamic (shared) libraries?

Advanced
A static library (.a/.lib) is copied into the executable at link time—larger binary, no runtime dependency, updates require relinking. A dynamic/shared library (.so/.dll) is linked at load/run time—smaller executables, shared across programs, updatable without relinking, but the library must be present at runtime and version compatibility matters. The choice trades deployment simplicity against flexibility and size.
g++ main.o -lmylib          # link against libmylib (static or shared)
Real-world example Shipping a plugin as a shared library lets it be updated without rebuilding the host application.

Common follow-ups: When is static linking preferable? | What runtime requirement do shared libraries add?

Compilation & Linking Compilation & Linking Compilation & Linking

Why do you need include guards or #pragma once, in linkage terms?

Intermediate
Headers are textually included into every translation unit that uses them, potentially multiple times via transitive includes. Without guards, a header's declarations/definitions would be duplicated within one translation unit, causing redefinition compile errors. Guards ensure the header's contents appear once per translation unit, complementing the ODR across translation units.
Real-world example An unguarded header included twice in one .cpp triggers 'redefinition' errors the guard prevents.

Common follow-ups: What duplication do guards prevent? | How does this relate to the ODR?

Preprocessor & Macros Compilation & Linking Compilation & Linking

What are C++20 modules and how do they improve on headers?

Advanced
Modules (C++20) are a new way to organize code that replaces textual #include with a compiled, importable unit (import mymod;). They avoid repeatedly re-parsing headers (faster builds), don't leak macros or private details, remove include-order fragility, and give better encapsulation. Adoption is gradual as tooling matures, but modules address longstanding header/preprocessor problems.
export module math;
export int add(int a, int b);
// user: import math;
Real-world example Migrating heavy headers to modules cuts compile times by avoiding repeated header parsing.

Common follow-ups: How do modules speed up builds? | What header problems do they solve?

Preprocessor & Macros Modern C++ Compilation & Linking