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
#includeis expanded and every macro is replaced.staticat 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/#eliftake integer constant expressions built from macros; an undefined identifier evaluates to 0.defined Xis valid only inside#if/#elif.#errorstops the build;#linerewrites__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:bmisparses insideMAX(x,y) * 2and evaluates arguments twice.- Expecting a
const intvariable to work as acaselabel or a fixed array bound - in C it is not an integer constant expression;#defineor an enum is.