Intuition The big picture
Both macros and inline functions exist to avoid the cost of a normal function call for tiny, frequently-used operations. A normal function call has overhead: push arguments on the stack, jump, save registers, return, pop. For something like "square this number", the call may cost more than the work . So we ask the compiler/preprocessor to paste the code directly where it's used instead of jumping away.
The deep difference: a macro is text substitution by the preprocessor (it happens before the compiler even sees real C), while an inline function is a real function the compiler may choose to expand in place — keeping type checking, scoping, and a single evaluation of each argument.
Definition Macro (function-like)
A #define directive handled by the preprocessor . It does blind text replacement with no knowledge of C types, scope, or evaluation rules.
#define SQUARE ( x ) ((x) * (x))
Definition Inline function
A normal function with the inline keyword, suggesting the compiler copy its body into the call site to avoid call overhead — while still being a true, type-checked function.
static inline int square ( int x ) { return x * x; }
Intuition WHY macros are dangerous
Because the preprocessor only knows text , it cannot understand operator precedence or how many times your argument gets evaluated. The compiler-based inline function evaluates each argument exactly once and respects types.
Worked example Precedence trap
#define BAD ( x ) x * x // no parentheses
int r = BAD ( 2 + 3 ); // expands to 2 + 3 * 2 + 3
Why this step? Text substitution gives 2 + 3 * 2 + 3 = 2 + 6 + 3 = 11, not 25 25 25 .
Fix: parenthesize everything → #define SQ(x) ((x)*(x)) gives ((2+3)*(2+3)) = 25. ✅
Worked example Double-evaluation trap
#define SQ ( x ) ((x) * (x))
int i = 3 ;
int r = SQ (i ++ ); // expands to ((i++)*(i++))
Why this step? i++ appears twice , so i is incremented twice — undefined/unexpected result. An inline function square(i++) increments i once because the argument is evaluated before the call. ✅
Preprocessor runs first → expands #define macros (pure text).
Compiler then sees the expanded text → does type checking, then may inline functions.
So macros are resolved before type checking even begins; inline functions live inside the type system.
Aspect
Macro (#define)
Inline function
Handled by
Preprocessor
Compiler
Type checking
❌ None
✅ Full
Argument evaluated
Possibly multiple times
Once
Respects scope
❌ (global text)
✅
Debuggable / breakpoints
❌ Hard
✅ Yes
inline is a...
(n/a)
request , compiler may ignore
Has an address / can take &
❌
✅
Generic over types
✅ (works for any type)
❌ (one type, unless overloaded — not in C)
Intuition When each wins (80/20)
Inline function = default modern choice: safe, typed, debuggable.
Macro = when you need things a function can't do: type-generic code, stringizing #x, token-pasting a##b, or conditional compilation.
Worked example MAX as macro (type-generic but risky)
#define MAX ( a , b ) ((a) > (b) ? (a) : (b))
MAX (p ++ , q ++ ) // ⚠ one of p/q incremented twice
Why this step? Whichever wins the ?: is re-evaluated when "returned". Double evaluation again.
Worked example MAX as inline (safe)
static inline int imax ( int a , int b ) { return a > b ? a : b; }
imax (p ++ , q ++ ); // each evaluated exactly once ✅
Why this step? Arguments p++, q++ are computed once into the parameters before the body runs.
Common mistake Steel-man the common errors
"inline guarantees the function is inlined."
Why it feels right: the keyword literally says "inline." The truth: inline is only a hint ; the compiler may ignore it (e.g. recursive or large functions). It also affects linkage rules, not a hard inlining order. Fix: rely on the compiler's optimizer; use inline for intent, not control.
"Macros are always faster than functions."
Why it feels right: no call overhead. The truth: an inline function also has no call overhead when inlined, and avoids re-evaluating arguments, often producing better code. Fix: prefer inline; reach for macros only for non-function powers.
"A macro needs a semicolon like a statement."
Why it feels right: it looks like code. The truth: #define MAX(a,b) (...) is an expression; adding a ; inside the define breaks expressions. For multi-statement macros use the do { ... } while(0) idiom.
do{...}while(0) idiom
#define SWAP ( a , b , T ) do { T t = (a); (a) = (b); (b) = t; } while ( 0 )
if (x) SWAP (p,q, int ); else foo (); // works correctly
Why this step? Wrapping in do{...}while(0) makes a multi-statement macro behave like a single statement, so the if/else pairing stays valid and the trailing ; is consumed.
Recall Explain it to a 12-year-old (hidden)
Imagine a recipe says "add SQUARE(amount of sugar)". A macro is like a careless helper who literally writes your words again — if you said "1+1 cups", he writes "1+1 × 1+1 cups" and gets the math wrong. An inline function is a smart helper who first figures out you meant 2 cups, then squares it to 4 — every time, correctly. Both save you a trip to a faraway kitchen (the function call), but the smart helper doesn't mess up.
"Pre-Paste, Com-Check."
Macro = Preprocessor Pastes text (Parens + double-eval Perils).
Inline = Compiler Checks types (Counts each arg once).
Who processes a macro vs an inline function?
Why does #define SQ(x) x*x break with SQ(2+3)?
Why is SQ(i++) dangerous as a macro but safe as an inline function?
Is inline a guarantee?
Who handles macros, preprocessor or compiler? The preprocessor — pure text substitution before compilation.
Who handles inline functions? The compiler , which may expand the body at the call site.
Why must macro parameters and the whole body be parenthesized? To preserve operator precedence; text substitution otherwise breaks expressions like SQ(2+3).
What does SQ(2+3) expand to with #define SQ(x) x*x? 2+3*2+3 = 11, not 25.
Why is SQ(i++) unsafe as a macro? i++ is substituted twice → (i++)*(i++), evaluating the side effect twice (undefined/unexpected).
How many times does an inline function evaluate each argument? Exactly once — arguments are computed before the body runs.
Is inline a command or a request? A request/hint ; the compiler may ignore it.
Give one thing macros can do that functions cannot. Type-generic code, stringizing #x, token pasting ##, or conditional compilation.
Which is easier to debug, macro or inline function? Inline function — you can set breakpoints and it respects scope/types.
What idiom makes a multi-statement macro a single safe statement? do { ... } while(0).
C Preprocessor — #define, #include, conditional compilation
Operator Precedence in C — why macro parens matter
Function Call Overhead — the cost both techniques remove
Undefined Behavior in C — double-evaluation side effects
const and constexpr — typed alternatives to constant macros
Compiler Optimization — when inline is actually honored
Intuition Hinglish mein samjho
Dekho, dono cheezein — macros aur inline functions — ek hi problem solve karti hain: chhote-chhote operations ke liye normal function call ka overhead bachana. Lekin kaam karne ka tareeka bilkul alag hai. Macro ko preprocessor handle karta hai, matlab woh sirf text copy-paste karta hai, usse C ke types ya brackets ki koi samajh nahi. Isliye #define SQ(x) x*x likho aur SQ(2+3) call karo, to woh ban jaata hai 2+3*2+3 = 11, na ki 25. Solution: har cheez ko bracket mein lapeto — ((x)*(x)).
Inline function ko compiler handle karta hai. Yeh ek asli function hai jisme type checking hoti hai, scope respect hota hai, aur sabse important — har argument sirf ek baar evaluate hota hai. Macro mein SQ(i++) likho to i do baar badh jaata hai (bug!), par inline function mein i ek hi baar badhega. Isi wajah se modern C mein default choice inline function hai — safe, debuggable, predictable.
Ek important baat: inline keyword sirf ek request hai, guarantee nahi. Compiler chaahe to ignore kar de (jaise recursive ya bade function mein). Toh inline ka matlab "main chahta hoon yeh inline ho" — control compiler ke paas hai. Macro tab use karo jab function se kuch na ho paaye, jaise type-generic code, #x stringizing, ya a##b token pasting.
Yaad rakhne ka simple rule: "Pre-Paste, Com-Check" — Macro = Preprocessor sirf paste karta hai (parentheses aur double-evaluation ke traps ke saath), Inline = Compiler types check karta hai aur har argument ek baar ginta hai. Exam aur real coding dono mein yeh difference bahut puchha jaata hai.