TRT
Sign in
easyFoundationsconcept

Why can including the same header twice break a build?

Explain headers, translation units, include guards, and the split between undefined references and duplicate definitions.

TRT practice prompt — not a verified question from a named employer.

The Runtime Theory Team2 min read
Learn it firstSplitting a Program Across Files: Headers and Include GuardsSplit a program into headers and source files, build it as separate translation units, understand what an include guard does, and learn what belongs in a header and what causes multiple-definition errors.

A strong answer

A strong candidate frames Why can including the same header twice break a build? around the exact memory layout, compiler semantics, and hardware execution model covered in Splitting a Program Across Files: Headers and Include Guards. Explain headers, translation units, include guards, and the split between undefined references and duplicate definitions.

A program in one file works until it grows. Then every small change recompiles everything, several people cannot work on it at once, and nothing can be reused in another program. The solution is to split it across files. But the compiler compiles one file at a time, and while it compiles main.cpp, it cannot see the body of a function that lives in another file.

So how can main.cpp call square at all? You already know the ingredients from lesson 1, which separated a declaration, a promise that something exists, from a definition, which supplies its body, and which gave the linker the job of joining the pieces. This lesson turns them into a working project layout.

In a production interview, always connect the specification rule to its concrete runtime consequence: state what lives on the stack versus the heap or static storage segment, how the compiler or operating system validates alignments, lifetimes, and error codes, and what happens under adversarial or boundary inputs (such as zero-length buffers, integer overflow, concurrent mutation, or partial I/O). Backing your explanation with a small trace of register/memory state transitions immediately separates senior systems engineers from candidates who only memorized syntax.

What the interviewer is listening for

  • Mastery of core invariant: Divide a small program into a header, an implementation file and a main file, and build it.
  • Mastery of core invariant: Explain what an include guard does and why a header can reach the compiler twice.
  • Mastery of core invariant: Decide what belongs in a header and what causes a multiple-definition error.
  • Hardware and ABI awareness: Explaining how sizes, alignments, calling conventions, or kernel boundaries behave on real 64-bit targets rather than relying on implementation-defined assumptions.
  • Defensive engineering: Naming the exact compiler flags (-Wall -Wextra -Werror), static analyzers, or runtime sanitizers (-fsanitize=address,undefined,thread) that verify correctness in CI.

Common mistakes

  • Explaining only surface syntax without tracing the underlying memory addresses, ownership lifetime, or kernel/user-space state transitions.
  • Assuming undefined behavior (such as signed overflow, uninitialized reads, strict-aliasing violations, or dangling pointers) will "just work" because it passed an unoptimized -O0 debug build.
  • Ignoring return codes, partial reads/writes, alignment padding, or cleanup paths when an allocation or syscall fails midway through a function.

This answer walks

Practice follow-ups

  1. 01What belongs in a header against what must live in exactly one source file?

Not started

Sign in to save your learning progress.

Sign in to save