C CLP study materials
C CLP study resources

C CLP: Program Structure, Compilation, and Preprocessing

C CLP · Work through your exam, one topic at a time.

All guide sections

Program Structure, Compilation, and Preprocessing

The exam uses this domain to check that you can follow a C source file through preprocessing, compilation, and linking, and predict exactly what the preprocessor substitutes before the compiler parses anything.

Translation phases and translation units

  • Line splicing (a backslash at the end of a line) happens first, then comments become a single space, then the text is split into preprocessing tokens.
  • A translation unit is one source file after every #include is expanded and every macro is replaced. static at file scope limits a name to its translation unit; a non-static definition is visible to the linker.
  • A declaration introduces a name; a definition allocates storage or supplies a body. int x; at file scope is a tentative definition; extern int x; is a declaration only.

Directives you must know cold

  • #include "file" searches the current file's directory first (implementation-defined beyond that); #include <file> uses the implementation's header search path. Include guards (#ifndef H / #define H / #endif) are more portable than #pragma once.
  • Function-like macros expand only when followed by (. # stringizes the unexpanded parameter; ## pastes tokens without expanding them first.
  • #if/#elif take integer constant expressions built from macros; an undefined identifier evaluates to 0. defined X is valid only inside #if/#elif. #error stops the build; #line rewrites __LINE__/__FILE__.

Worked example

#define SQR(x) x*x
int r = SQR(1+2);

Token substitution gives 1+2*1+2, which parses as 1 + (2*1) + 2 = 5, not 9. Parenthesize both the parameters and the whole body: #define SQR(x) ((x)*(x)). That still evaluates the argument twice, so SQR(i++) increments i twice, and because the two uses are unsequenced the program has undefined behaviour. A single-evaluation-safe version must be an inline function or a macro using a temporary.

Traps

  • No semicolon after #define; a stray trailing ; becomes part of the replacement text.
  • Macro names have no scope: they leak from the point of definition to the end of the translation unit or #undef.
  • #define MAX(a,b) a>b?a:b misparses inside MAX(x,y) * 2 and evaluates arguments twice.
  • Expecting a const int variable to work as a case label or a fixed array bound - in C it is not an integer constant expression; #define or an enum is.