C ยท Chapter 36 of 45

C Preprocessor and Macros

The preprocessor runs before actual compilation, handling directives that start with #, like #include and #define. It performs text substitution and conditional inclusion of code.

Macros defined with #define can be simple constants or function-like macros that take arguments, though they should be used carefully since they're just textual substitutions.

Syntax
#define NAME value
#define MACRO(x) ((x) * (x))

Object-like and function-like macros

A simple `#define PI 3.14` substitutes PI with 3.14 everywhere. A function-like macro like `#define SQUARE(x) ((x) * (x))` takes parameters, but expands as plain text, so parentheses around parameters are important.

Conditional compilation

#ifdef, #ifndef, #else and #endif let you include or exclude code based on whether a macro is defined, which is commonly used for header guards and platform-specific code.

Example 1 (c)
#include <stdio.h>
#define SQUARE(x) ((x) * (x))

int main() {
  printf("%d\n", SQUARE(5));
  return 0;
}
Output
25

SQUARE(5) expands to ((5) * (5)) before compilation, giving 25.

Example 2 (c)
#include <stdio.h>
#define DEBUG

int main() {
#ifdef DEBUG
  printf("Debug mode\n");
#endif
  return 0;
}
Output
Debug mode

The block only compiles into the program because DEBUG was defined above.

Key points

  • Preprocessor directives start with # and run before compilation.
  • #define creates simple or function-like macros via text substitution.
  • Always wrap macro parameters in parentheses to avoid precedence bugs.
  • #ifdef/#ifndef/#endif enable conditional compilation.
๐Ÿ’ก Note: Prefer inline functions or const/enum over macros when type safety matters, since macros are unaware of C's type system.

๐Ÿ“ Quick Quiz

1. When does the preprocessor run relative to compilation?

2. Why should macro parameters be wrapped in parentheses?

3. Which directive checks if a macro is defined?