Shiklo Tools
PDF40
Image20
Calculators & Converters25
Text & Writing13
Developer26
Video14
Audio14
Document14
Data & Spreadsheet12
Web & SEO9
OCR & Scanning5
Archive & File12
Security & Privacy23
Health & Medical29
QR & Barcode5

C Preprocessor and Macros

Before the compiler sees your code, the preprocessor reads it and acts on every line that starts with #. It includes files, replaces names with values and can leave parts of the code out. It works on text, without knowing C's types or rules.

#include

#include <file.h> pastes a header from the system's libraries into your file. #include "file.h", with quotes, first looks for the file in your project. The Header Files topic uses this for your own code.

#define constants

#include <stdio.h>

#define SIZE 5
#define TITLE "Squares"

int main(void) {
    int a[SIZE];
    printf("%s:", TITLE);
    for (int i = 0; i < SIZE; i++) {
        a[i] = i * i;
        printf(" %d", a[i]);
    }
    printf("\n");
    return 0;
}
Output
Squares: 0 1 4 9 16

Function-like macros

A macro can take arguments. The preprocessor replaces the text, so put brackets around every argument and around the whole result, or operator precedence surprises you:

#include <stdio.h>

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

int main(void) {
    printf("SQUARE_BAD(2 + 3) = %d\n", SQUARE_BAD(2 + 3));
    printf("SQUARE(2 + 3)     = %d\n", SQUARE(2 + 3));
    printf("MAX(7, 12)        = %d\n", MAX(7, 12));
    return 0;
}
Output
SQUARE_BAD(2 + 3) = 11
SQUARE(2 + 3)     = 25
MAX(7, 12)        = 12

SQUARE_BAD(2 + 3) becomes 2 + 3 * 2 + 3, which is 11. Even with brackets, a macro evaluates its argument more than once: SQUARE(i++) increments i twice. In modern C, a small function (possibly marked inline) is usually the safer choice; keep macros for constants and conditional compilation.

Conditional compilation

#if, #ifdef, #ifndef, #else and #endif keep or drop code before compiling. A common use is extra output while debugging:

#include <stdio.h>

#define DEBUG 1

int main(void) {
    int total = 0;
    for (int i = 1; i <= 3; i++) {
        total += i;
#if DEBUG
        printf("[debug] i = %d, total = %d\n", i, total);
#endif
    }
    printf("total = %d\n", total);
    return 0;
}
Output
[debug] i = 1, total = 1
[debug] i = 2, total = 3
[debug] i = 3, total = 6
total = 6

Change DEBUG to 0 and the debug lines are not even compiled. A setting can also come from the compiler command: gcc -DDEBUG=1 main.c.

Built-in macros

The preprocessor provides __FILE__ and __LINE__ (the current file name and line number), and __DATE__ and __TIME__ (when the program was compiled). They are handy in error messages: printf("error in %s line %d\n", __FILE__, __LINE__);.

Practice exercises

  1. Write a macro ABS(x) for the absolute value with the right brackets, and test it with ABS(-3 - 4).
  2. Use #ifdef to print a message only when VERBOSE is defined, and switch it on with -DVERBOSE.
  3. Call SQUARE(i++) and print i afterwards. Explain the result.