5.1.28 · D3 · HinglishC Programming

Worked examplesMacros vs inline functions

3,032 words14 min read↑ Read in English

5.1.28 · D3 · Coding › C Programming › Macros vs inline functions

Shuru karne se pehle, ek anchor jo hum baar baar use karenge:


Scenario matrix

Har macro/inline problem jo tumhe milegi woh in cells mein se ek hai. Neeche har worked example pe us cell ka tag lagaa hai, aur milake yeh poora grid cover karte hain.

# Case class Kya galat ho sakta hai Covered by
A Precedence — arithmetic argument x*x bina parens ke galat bind karta hai Ex 1
B Precedence — surrounding operators bahar ka -, / un-parenthesized body ko grab karta hai Ex 2
C Side effect / double evaluation i++, p++ do baar evaluate hota hai Ex 3
D Zero / degenerate input 0, empty, one-argument Ex 4
E Type behaviour (macro vs inline) int-vs-double, truncation, generic-ness Ex 5
F Control-flow embedding if/else + multi-statement macro Ex 6
G Real-world word problem real constraints mein sahi tool chunna Ex 7
H Exam-style twist ek hi line mein nested / mixed traps Ex 8

Example 1 — Cell A: argument ke andar precedence

Steps

  1. Literal text 2 + 3 ko x ki jagah substitute karo. Yeh step kyun? Preprocessor characters copy karta hai, toh SQ(2 + 3) ban jaata hai (2 + 3 * 2 + 3).
  2. Ab result compiler ko do, jo real Operator Precedence in C apply karta hai: * pehle + se. Yeh step kyun? Precedence compiler ka kaam hai, substitution ke baad apply hoti hai. Toh 2 + 3*2 + 3 = 2 + 6 + 3.
  3. Left to right add karo: . Yeh step kyun? Saare operators ab + hain, associativity left-to-right hai, order sum nahi badalta.

Verify: , nahi. Yaad raho: body ke baahir outer parens ne hume nahi bachaaya — danger do x uses ke beech tha. Asli fix hai #define SQ(x) ((x)*(x)), jo deta hai ((2+3)*(2+3)) = 25.


Example 2 — Cell B: macro ke bahar precedence

Steps

  1. 4 ko x ki jagah substitute karo: line ban jaati hai 10 - 4 / 2. Yeh step kyun? Blind paste — HALF(4) gayab, 4 / 2 us jagah aa jaata hai, bina brackets ke.
  2. Precedence apply karo: / - se zyada tight bind karta hai, toh hai 10 - (4/2). Yeh step kyun? Yahan kismet se kaam bana — / - se upar hai, toh yeh particular case safe nikla.
  3. Ab surrounding operator badlo: int r = HALF(4) * 3; ban jaata hai 4 / 2 * 3 = (4/2)*3 = 6, aur tumhe bhi chahiye tha... jo 6 hi hai. Try karo int r = 12 / HALF(4);12 / 4 / 2 = (12/4)/2 = 1, lekin tumhe chahiye tha . Ab toot gaya. Yeh step kyun? Un-parenthesized body ek landmine hai jo sirf kuch surrounding operators ke liye phatta hai. Yahi unpredictability rule ki wajah hai — "poore body ko bhi parenthesize karo": #define HALF(x) ((x)/2).

Verify: safe macro ke saath, 12 / ((4)/2) = 12 / 2 = 6. ✅ Moral: har parameter AUR poori body ko wrap karo.


Example 3 — Cell C: double-evaluation trap

Steps

  1. Text i++ ko x ki jagah substitute karo: r = ((i++)*(i++));. Yeh step kyun? x body mein do baar aata hai, isliye side-effecting text i++ do baar paste hota hai.
  2. Side effects count karo: do i++ operations matlab i do baar increment hoga. Lekin kab har ek read hoga, aur kis order mein, yeh Undefined Behavior in C hai — C standard koi guaranteed value nahi deta. Yeh step kyun? Parentheses sirf grouping fix karte hain; side effect ko un-duplicate nahi kar sakte. Ek typical compiler pe tumhe r = 3*4 = 12 ya 3*3 = 9 dikh sakta hai — lekin kabhi rely mat karo.
  3. Ab inline version: static inline int sq(int x){ return x*x; } phir sq(i++). Yeh step kyun? Argument i++ exactly ek baar evaluate hota hai parameter value 3 produce karne ke liye, aur tab i 4 ho jaata hai. Body ke andar x*x = 3*3 = 9, deterministically.

Verify: inline deta hai r = 9, i = 4, guaranteed. Macro undefined results deta hai (double increment). Yeh inline prefer karne ka sabse strong argument hai — dekho Function Call Overhead (jo inline bhi remove karta hai jab compiler expand karta hai).


Example 4 — Cell D: zero aur degenerate inputs

Steps

  1. POS(0)((0) < 0 ? 0 : (0)). 0 < 0 false hai, toh ternary 0 yield karta hai. Yeh step kyun? Boundary value 0, 0 se kam nahi hai, toh unchanged rehta hai — sahi.
  2. POS(-5)((-5) < 0 ? 0 : (-5)). -5 < 0 true → 0 yield karta hai. Yeh step kyun? Negative input clamp ho jaata hai, jaisa intended tha.
  3. POS(-3 + 3)(((-3 + 3)) < 0 ? 0 : ((-3 + 3))). Inner value 0 hai, 0 < 0 false → 0 yield karta hai. Yeh step kyun? Kyunki har x parenthesized hai, sum -3 + 3 comparison se pehle ek group ki tarah evaluate hota hai. Bina inner parens ke, -3 + 3 < 0 yahan bhi kaam karta, lekin POS(a & b) type expressions galat bind karte — degenerate arithmetic argument confirm karta hai ki hamare parens sahi hain.

Verify: POS(0)=0, POS(-5)=0, POS(-3+3)=0. Saare . ✅ Degenerate/boundary inputs pass hote hain kyunki ternary < (strict) use karta hai, toh 0 khud pe hi map hota hai.


Example 5 — Cell E: type behaviour, macro vs inline

Steps

  1. CUBE(2.5)((2.5)*(2.5)*(2.5)). Kyunki 2.5 ek double literal hai, compiler floating multiplication karta hai. Yeh step kyun? Macro ka apna koi type nahi — jo type argument ke text mein hai wahi inherit karta hai. Toh .
  2. icube(2.5): parameter int x hai, toh 2.5 int mein convert hota hai, body run hone se pehle 2 mein truncate hokar. Yeh step kyun? Inline function fully type-checked hota hai. 2.5 ko int x mein pass karna use 2 mein narrow karta hai, phir .
  3. Compare karo: macro = 15.625, inline = 8. Yeh step kyun? Yeh double-edged sword hai. Macro generic hai (double ke liye bhi kaam karta hai), inline type-safe hai (int pe commit karta hai). Dono "galat" nahi — zaroorat ke hisaab se choose karo. Dekho const and constexpr typed constant alternatives ke liye.

Verify: (macro, double raha); 2.5 ka int truncation hai 2, (inline). ✅


Example 6 — Cell F: control-flow embedding

Steps

  1. Substitute karo: if body ban jaata hai x = 0; y = 0;. Toh poora text hai:
    if (flag)
        x = 0; y = 0;      // <-- do statements!
    else
        z = 1;
    Yeh step kyun? Bina braces ka if sirf agle single statement ko leta hai — woh hai x = 0;. Ab y = 0; ek alag statement hai jo hamesha run karta hai, aur yeh if aur else ke beech baithaa hai.
  2. Compiler else dekhta hai bina matching if ke → syntax error (error: 'else' without a previous 'if'). Yeh step kyun? Do statements paste karne se jahan ek ki zaroorat thi, if/else pairing toot gayi.
  3. do{...}while(0) idiom se fix karo:
    #define RESET(a,b) do { (a) = 0; (b) = 0; } while(0)
    Ab RESET(x,y); expand hota hai do{ (x)=0; (y)=0; } while(0); mein — ek syntactic statement, aur baad ka ; cleanly consume ho jaata hai. Yeh step kyun? do{...}while(0) kai statements ko exactly ek statement mein bundle karta hai jo ek following semicolon bhi swallow karta hai, toh yeh if/else mein normal call ki tarah slot ho jaata hai.

Verify: idiom ke saath, if(flag) RESET(x,y); else z=1; sahi parse hota hai: flag true dono assignments run karta hai, false z=1 run karta hai. ✅


Example 7 — Cell G: real-world word problem

Steps

  1. Substitute karo: ((next()) > (threshold) ? (next()) : (threshold)). Yeh step kyun? a = next() do baar aata hai. Toh next() ek baar comparison mein call hota hai aur, agar jeet jaaye, dobara "return" karte waqt.
  2. Case split. Agar next() <= threshold: next() ek baar run karta hai (comparison), aur : branch threshold return karta hai. Agar next() > threshold: next() do baar run karta hai (comparison aur ? branch) — aur har call stream ko advance karti hai, toh woh comparison mein jeete value se alag, baad ki value return karta hai. Yeh step kyun? Bug intermittent hai kyunki yeh sirf tab bite karta hai jab next() > threshold. Isliye yeh "kabhi kabhi kaam karta hai." Classic double-evaluation, bilkul Cell C lekin ek real call ke andar chupaaya hua.
  3. Fix — inline function, jo har argument ek baar evaluate karta hai:
    static inline int imax(int a, int b){ return a > b ? a : b; }
    int v = next();
    total += imax(v, threshold);   // next() exactly ek baar call hua
    Yeh step kyun? Inline version next() ko ek baar a mein compute karta hai, guarantee karta hai ki compared value aur returned value same hai. -O2 ke saath yeh same fast code mein inline ho jaata hai — zero call overhead aur correct bhi.

Verify (numeric): maano stream successive calls pe 10, 99 yield karta hai aur threshold = 5 hai. Macro: comparison call 10 padhta hai (10 > 5 true), return call 99 padhta hai → 99 contribute karta hai (galat, aur ek extra stream value kha jaata hai). Inline: 10 ek baar padhta hai, 10 > 510 contribute karta hai (sahi). ✅


Example 8 — Cell H: exam-style twist (nested traps)

Steps

  1. SQ(a - b) → har x ki jagah text a - b substitute karo: a - b * a - b. Yeh step kyun? Blind paste, inner parens nahi → 4 - 2*4 - 2.
  2. Precedence apply karo (* - se pehle): 4 - (2*4) - 2 = 4 - 8 - 2 = -6. Yeh step kyun? Beech ka * b aur a steal kar leta hai, subtraction grouping barbad kar deta hai.
  3. Ab SQ(a - b) * 2a - b * a - b * 2 = 4 - 2*4 - 2*2 = 4 - 8 - 4 = -8. Yeh step kyun? Baad ka * 2 sirf aakhiri pasted b se bind karta hai, poore result se nahi — ek chautha surprise. Intended kahin nahi hai.
  4. Correct macro #define SQ(x) ((x)*(x)): SQ(a-b)((4-2)*(4-2)) = 4; SQ(a-b)*2((4-2)*(4-2))*2 = 8. Yeh step kyun? Full parenthesization (har param + poori body) dono cases ko intended algebra se match karaata hai.

Verify: buggy: SQ(a-b) = -6, SQ(a-b)*2 = -8. Fixed: 4 aur 8. ✅ Har trap text substitution + precedence pe trace hota hai.



Recall checkpoint

Recall Answers

Q1 ::: Danger do xs ke beech hai (2+3 * 2+3); sirf per-parameter parens ((x)*(x)) fix karte hain, body wrap karne se kuch nahi hota. Q2 ::: 12/4/2 = 1 ban jaata hai (left-to-right) instead of 12/(4/2)=6; fix hai ((x)/2). Q3 ::: Macro i++ do baar paste karta hai → do side effects, order unspecified → UB; inline argument ek baar evaluate karta hai body se pehle. Q4 ::: 0 return karta hai; 0 < 0 false hai toh 0 khud pe map hota hai — strict < boundary ko sahi rakhta hai. Q5 ::: Macro typeless text hai → 2.5 double rehta hai → 15.625; inline int x 2.52 truncate karta hai → 8. Q6 ::: do { ... } while(0).


Connections

  • Parent: Macros vs inline functions
  • C Preprocessor — blind text substitution karne wala engine
  • Operator Precedence in C — kyun har example precedence pe turn karta hai
  • Function Call Overhead — woh cost jo inline remove karta hai safe rehte hue
  • Undefined Behavior in C — double-evaluation cases
  • const and constexpr — constant macros ke typed alternatives
  • Compiler Optimization — inline kab actually honor hota hai (Ex 7)

Concept Map

fix

fix

fix

Macro call text

Preprocessor pastes text

Precedence trap

Double evaluation trap

Multi statement trap

Parenthesize param and body

Use inline eval once

do while zero idiom

Inline function

Type checked eval once