📘 Lesson  ·  Lesson 60

Macros & Preprocessor

What is a macro? (quick recap)

A macro is a rule you create with #define that the C preprocessor uses to replace text in your code before the compiler runs. If preprocessor basics like #include and include guards are new to you, read preprocessor directives first. This lesson focuses specifically on macros — the most powerful and most dangerous part of the preprocessor.

Object-like macros (constants)

The simplest macros just give a name to a fixed value. These are called object-like macros.

C Language
#include <stdio.h>
#define PI 3.14159
#define GREETING "Hello!"

int main() {
    printf("PI = %f\n", PI);
    printf("%s\n", GREETING);
    return 0;
}
Output:
PI = 3.141590
Hello!

Before compiling, the preprocessor literally replaces every PI with 3.14159 and every GREETING with "Hello!".

Function-like macros

Macros can also take arguments, looking a lot like functions — but they are still just text replacement.

C Language
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

int main() {
    printf("Square = %d\n", SQUARE(5));
    printf("Max = %d\n", MAX(10, 20));
    return 0;
}
Output:
Square = 25
Max = 20

Why parentheses are critical

This is the number-one macro trap. Because macros are blind text substitution, missing parentheses can silently give wrong answers.

C Language
#include <stdio.h>
#define BAD(x)  x * x        // no parentheses
#define GOOD(x) ((x) * (x))  // safe

int main() {
    printf("BAD(2+3)  = %d\n", BAD(2+3));   // 2+3*2+3 = 11
    printf("GOOD(2+3) = %d\n", GOOD(2+3));  // (2+3)*(2+3) = 25
    return 0;
}
Output:
BAD(2+3) = 11
GOOD(2+3) = 25
⚠️ Rule

In a function-like macro, wrap every argument and the whole body in parentheses. This single habit prevents most macro bugs.

The # and ## operators

Two special operators exist only inside macros. # turns an argument into a string; ## pastes two tokens together.

C Language
#include <stdio.h>
#define SHOW(x)   printf(#x " = %d\n", x)   // stringize
#define JOIN(a,b) a ## b                    // token paste

int main() {
    int value = 42;
    SHOW(value);            // prints: value = 42

    int JOIN(my, Num) = 7;  // becomes: int myNum = 7;
    printf("myNum = %d\n", myNum);
    return 0;
}
Output:
value = 42
myNum = 7

Notice how #x printed the text "value", and JOIN(my, Num) built the identifier myNum.

Macros vs functions

PointMacroFunction
When it runsBefore compilation (text)At run time
Type checkingNoneYes
SpeedNo call overheadSmall call overhead
DebuggingHardEasy
Side-effect safetyRiskySafe

Dangerous pitfalls

Beyond missing parentheses, macros have another classic trap: arguments used more than once can be evaluated more than once.

C Language
#include <stdio.h>
#define SQUARE(x) ((x) * (x))

int main() {
    int n = 4;
    printf("%d\n", SQUARE(n++));  // becomes ((n++) * (n++)) -- unsafe!
    return 0;
}
⚠️ Double evaluation

Because SQUARE(n++) expands to ((n++) * (n++)), n is incremented twice and the result is undefined. Never pass expressions with side effects (like n++) to a macro. A real function would not have this problem.

Summary

  • A macro is a #define text-replacement rule handled before compilation.
  • Object-like macros name constants; function-like macros take arguments.
  • Always parenthesise every argument and the whole macro body.
  • # stringizes an argument; ## pastes tokens together.
  • Macros have no type checking and can double-evaluate arguments — prefer functions when in doubt.

Frequently Asked Questions

What is a macro in C?
A macro is a name created with #define that the preprocessor replaces with a piece of text before compilation. It can be a simple constant like #define PI 3.14, or a function-like macro that takes arguments. The compiler never sees the macro name — only its replacement text.
What is the difference between a macro and a function in C?
A function is real code that runs at run time with its own memory and type checking. A macro is a pure text replacement done before compilation, with no type checking and no function-call overhead. Macros can be faster for tiny operations but are error-prone, while functions are safer and easier to debug.
Why must function-like macros use so many parentheses?
Because a macro is blind text substitution, missing parentheses let surrounding operators change the intended order. For example #define SQ(x) x*x turns SQ(2+3) into 2+3*2+3 = 11, not 25. Wrapping every argument and the whole body in parentheses — ((x)*(x)) — prevents this.
What do the # and ## operators do in macros?
The # operator turns a macro argument into a string ("stringize"), so #x becomes "x". The ## operator glues two tokens into one ("token pasting"), so a ## b becomes ab. They are used in advanced macros for generating names and debug messages.
Are macros considered bad practice in C?
Not inherently, but they should be used carefully. For constants, many programmers now prefer const or enum, and for small operations an inline function is safer. Macros remain useful for conditional compilation and a few tasks functions cannot do, but overusing complex macros makes code hard to read and debug.
← Back to C Tutorial
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 Live Code Editor

This page's programs are ready here — run them, edit them, and learn. No installation needed.
Powered by OneCompiler. The code loads into the editor automatically — press Run to see the output. If the editor does not open, open it in a new tab.