Macro output questions look like arithmetic, but they are really about text. The preprocessor substitutes tokens before the compiler applies C syntax, precedence and evaluation rules. It adds no helpful types or parentheses of its own.
Once you separate expansion from evaluation, the common #define traps stop looking mysterious. You can write the expanded expression first and solve it like any other C expression.
What the C preprocessor does and does not do
The preprocessor runs before compilation. Its familiar jobs include processing #include, replacing #define macros and selecting code through directives such as #ifdef, #ifndef and #endif.
An object-like macro associates a name with replacement text:
#define PI 3.14A function-like macro accepts parameters:
#define SQUARE(x) x*xThe second form looks like a function call, but it is not one. The preprocessor pastes the supplied argument text wherever x occurs in the replacement list. It does not type-check the argument, evaluate it first or create a callable function with an address.
Macros also do not follow ordinary block scope. A definition remains active from its definition point until it is undefined with #undef or the preprocessing unit ends. That wide reach is one reason poorly named macros can cause surprising collisions.
Worked example 1: the parenthesization trap
Start with the unsafe definition:
#define SQUARE(x) x*x
int r = SQUARE(1+2);Do not calculate 1 + 2 first. Substitute the text exactly:
int r = 1+2*1+2;Multiplication has higher precedence than addition, so the steps are:
2 * 1 = 21 + 2 + 2 = 5
Therefore, r is 5, not the expected 9.
Now use the same macro inside division:
int s = 100 / SQUARE(5);Expansion produces 100 / 5*5. Division and multiplication have the same precedence and associate from left to right:
100 / 5 = 2020 * 5 = 100
Therefore, s is 100, not 4.
The safe definition parenthesises every parameter occurrence and the complete replacement expression:
#define SQUARE(x) ((x)*(x))Now SQUARE(1+2) becomes ((1+2)*(1+2)). Each sum is 3, so 3 * 3 = 9. Likewise, 100 / SQUARE(5) becomes 100 / ((5)*(5)), then 100 / 25 = 4.
The preprocessor supplies the text; precedence decides what that text means. Keep the table in Operator Precedence and Associativity in C beside you while you expand.

Worked example 2: multiple argument evaluation
Parentheses fix grouping, but they do not prevent a parameter from appearing more than once. Consider:
#define MAX(a,b) ((a)>(b)?(a):(b))
int i = 5, j = 8;
int m = MAX(i++, j++);The expansion is:
int m = ((i++)>(j++)?(i++):(j++));Trace only the operands that C evaluates:
The condition evaluates
i++. It yields5, thenibecomes6.The condition evaluates
j++. It yields8, thenjbecomes9.5 > 8is false, so only the conditional operator's else expression runs.The else expression evaluates
j++. It yields9, thenjbecomes10.
The final state is m = 9, i = 6 and j = 10. The argument containing j++ was evaluated twice. The macro has not returned the maximum of the original values in the way a programmer would reasonably expect.
A real function receives values after each argument expression has been evaluated once. This does not make every expression with multiple side effects safe, because C's evaluation-order rules still matter, but it does remove the macro's repeated textual use of one parameter. Functions in C: Call by Value vs Pointers traces the same argument-passing question from the function side, where each argument is evaluated once before the body runs.
The working rule is simple: never pass i++, --j, an assignment or another side-effecting expression to a macro that may use its parameter more than once.
Macro vs function and the rest of the trap list

Property | Macro | Function |
|---|---|---|
Type checking | None during substitution | Checked through parameter and return types |
Argument use | Text may be pasted more than once | Each argument expression is evaluated once before the call |
Call overhead | No function call | A call may exist, though compilers can inline |
Debugging | Expansion can be hard to inspect | Function name and stack information are easier to follow |
Code size | Replacement can be repeated at every use | One function body, unless inlined |
Address | No callable address | Function address can be taken |
Parentheses are only the first safety check. Watch for these additional traps:
Trailing semicolon:
#define N 100;pastes the semicolon too.x = N + 1;becomesx = 100; + 1;, which is valid C but silently assigns100, not101(a compiler may warn that+1has no effect).Multiple statements: a macro containing several statements can break an enclosing
ifandelse. Wrap it indo { ... } while (0)so it behaves like one statement.Stringizing and token pasting:
#stringizes the raw, unexpanded argument into a string literal. For example, with#define PI 3.14,STR(PI)expands to"PI", not"3.14", whenSTR(x)is defined as#x. The##operator joins tokens instead. They are different operations.Name collisions: a macro name is not protected by ordinary C block scope.
No address:
&SQUAREcannot produce a function pointer becauseSQUAREis not a function.
Use functions for type safety, debugging and side-effect control. Use macros when preprocessing is actually needed, or when a carefully written constant or small pattern is justified.
How exams test macro expansion
GATE, CDAC C-CAT Section B, placement tests and viva questions usually show a short definition and ask for an output, expression value or error. The reliable method is always the same:
Copy the macro replacement body.
Substitute each argument as raw text.
Preserve every written parenthesis and add none mentally.
Apply C precedence, associativity and evaluation rules.
Track side effects one evaluation at a time.
The repeat offenders are the unsafe SQUARE family, side-effecting arguments in MAX, a semicolon inside a definition and a multi-statement macro that captures the wrong else.
None of this survives a guess. Write each expansion out character for character, then evaluate it with the precedence and side-effect rules, exactly as in the two traces above.
Macro output questions: solve these three
Cover the answers, expand each definition by hand, and only then compare.
Question 1. What does a hold?
#define CUBE(x) x*x*x
int a = CUBE(2+1);Answer: the expansion is 2+1*2+1*2+1. Multiplication binds tighter than addition, so the sum is 2 + 2 + 2 + 1, and a is 7, not 27. Defining the macro as ((x)*(x)*(x)) expands to ((2+1)*(2+1)*(2+1)) and gives 27.
Question 2. What does c hold?
#define LIMIT 50;
/* inside a function body */
int c = LIMIT + 5;Answer: the semicolon belongs to the replacement text, so the line becomes int c = 50; + 5;. That is a declaration followed by a separate + 5; statement, so c is 50, not 55. The fix is to drop the semicolon from the definition, never to add parentheses.
Question 3. What does d hold?
#define SQ(x) ((x)*(x))
int n = 3;
int d = SQ(n++);Answer: no value is guaranteed. The expansion is ((n++)*(n++)), which updates n twice inside one multiplication with nothing sequencing the two updates, so the behaviour is undefined. Contrast this with MAX(i++, j++) earlier: there i was updated once, and the two updates to j were separated by the conditional operator, so that trace had a definite answer. Parentheses cannot rescue SQ here, because the parameter still appears twice.
The short version and next step
The preprocessor substitutes text before compilation. Parenthesise every parameter and the whole replacement body, and never supply a side-effecting expression to a macro that can repeat it.
Build the full topic through the C Language Course: Concepts, MCQs & Coding, then use GATE Guidance by Sanchit Sir for exam framing. The Coding & DSA Courses for Placements path connects C output questions with the coding practice that follows them. Expand first, evaluate second, and the trap becomes a procedure.




