← C roadmap

Topic 11 of 15 · Advanced

Preprocessor & Macros

#define, macros, include guards and conditional compilation.

Concept

The preprocessor runs before compilation and does text substitution. #define creates constants and macros.

Function-like macros don't check types and can evaluate arguments twice — always wrap parameters and the whole body in parentheses.

Include guards (#ifndef/#define/#endif) or #pragma once stop a header being included twice. #ifdef enables debug-only code.

Code (C17)

#ifndef UTILS_H
#define UTILS_H

#define PI 3.14159
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

#ifdef DEBUG
  #define LOG(msg) printf("[debug] %s\n", msg)
#else
  #define LOG(msg)
#endif

#endif
/* SQUARE(i++) still increments twice - prefer inline functions */

Remember

  • Parenthesise macro parameters.
  • Macros have no type safety.
  • Use include guards in every header.

Interview questions

Macro vs inline function?

Macros are text substitution without type checks and may evaluate args twice; inline functions are type-checked real functions the compiler may inline.

Output of #define SQ(x) x*x; SQ(2+3)?

2+3*2+3 = 11, not 25 — because the parameter wasn't parenthesised.

Practise C with the AI mentor

Lesson test

Take an 8-question test on “Preprocessor & Macros” — concepts, output prediction, bug spotting and interview questions.

Can't find a C topic you need for exams or placements? Request it and we'll add it.