Macros are purely textual substitutions performed by the preprocessor at compile time, not at runtime. They don't allocate memory themselves.
Q.2Hard
What is the problem with this macro?
#define DOUBLE(x) x*x
int result = DOUBLE(2+3);
Answer: B
The macro expands to 2+3*2+3 = 2+6+3 = 11, not 25. This is because x is not parenthesized. Should use #define DOUBLE(x) ((x)*(x))
Q.3Hard
What will be the output?
#define MIN(a,b) ((a)<(b)?(a):(b))
int x=5; int y=10;
int z = MIN(x++, y++);
Answer: A
The macro expands to ((x++)<(y++)?(x++):(y++)). In the condition, x++ returns 5 and increments x to 6. Since 5<10 is true, x++ is evaluated again (x becomes 7, but z gets 6). Actually, this shows side effects problem - x becomes 7, y stays 10.
Q.4Hard
What is the difference between #if and #ifdef?
Answer: A
#ifdef checks if a macro is defined (exists). #if evaluates a constant integer expression (can check macro values, compare numbers, etc.).
Q.5Hard
What preprocessor features should be avoided for safer code?
Answer: B
Function-like macros can cause issues due to multiple evaluation of arguments and operator precedence problems. Modern C prefers inline functions and const for safety.
Advertisement
Q.6Hard
Consider:
#define MAX(a,b) ((a)>(b)?(a):(b))
Which advantage does this provide?
Answer: D
Macros with parentheses provide inline substitution (better performance, no function call overhead) and can work with any data type. However, they lack type safety that functions provide.
Q.7Hard
What will be output?
#define PRINT(x) printf(#x " = %d\n", x)
PRINT(5+3);
Answer: A
The # operator converts 5+3 into the string "5+3". The macro expands to printf("5+3" " = %d\n", 5+3) which prints: 5+3 = 8
Q.8Hard
What is the result of the following?
#define MIN(x,y) ((x)<(y)?(x):(y))
int a=5, b=3;
int result = MIN(a++, b++);
Answer: C
The macro expands to ((a++)<(b++)?(a++):(b++)). Since 5<3 is false, b++ is evaluated twice (once in comparison, once in ternary), making b=5. a is incremented once in comparison, so a=6.
Q.9Hard
What does the following preprocessor do?
#define OFFSET(type, field) ((size_t)&(((type *)0)->field))
Answer: A
This macro calculates the byte offset of a field within a structure by casting 0 as a pointer to the type and taking the address of the field. Similar to the offsetof() macro in stddef.h.
Q.10Hard
How many times is the argument evaluated in this macro?
#define CUBE(x) ((x)*(x)*(x))
int result = CUBE(a++);
Answer: C
The macro expands to ((a++)*(a++)*(a++)), so the argument a++ is evaluated 3 times. This demonstrates a critical problem with macros - side effects are repeated multiple times, leading to unexpected behavior.
Q.11Hard
What is a dangling macro problem in C?
Answer: C
A dangling macro typically refers to a macro that is defined but its usage may cause issues. More accurately, it's when a macro's scope or definition is unclear, especially in conditional compilation scenarios where #undef might cause problems.
Q.12Hard
Consider the following macro:
#define SWAP(a,b) {int temp=a; a=b; b=temp;}
What issue might occur with this macro?
Answer: D
While the macro works for all types (a and b are copied), the curly braces can cause issues when used in if-else statements without proper syntax (like missing semicolon after if). Additionally, it's limited to specific types. The safest answer is D regarding syntactic issues with placement.
Q.13Hard
What will happen if we define a macro with the same name as a C standard library function?
Answer: B
Macros are textual replacements that happen before compilation. If a macro has the same name as a library function, the macro replaces all occurrences of that name.
Q.14Hard
Consider the macro: #define AREA(r) 3.14*r*r
What is the issue and how to fix it?
Which of the following will correctly print the number of arguments passed to a variadic macro in C99?
Answer: A
C99 variadic macros don't have a built-in way to count arguments. Option A uses a clever technique with array size calculation. Option B references non-standard VA_NARGS. Options C and D use invalid syntax with token pasting.
Q.16Hard
Consider: #define SWAP(a,b) {int temp=a; a=b; b=temp;}
If used in an if-else without braces, which problem occurs?
if(condition) SWAP(x,y); else printf("No swap");
Answer: C
The macro expands to {int temp=a; a=b; b=temp;}; which ends with a semicolon. This creates: if(condition) {...}; else... The semicolon after the block makes else unreachable. The macro should use do-while(0) wrapper or be wrapped in a function.
Q.17Hard
What does the following preprocessor output?
#define VERSION "2024"
#define STR(x) #x
printf(STR(VERSION));
Answer: D
Stringification happens before macro expansion of arguments. STR(VERSION) becomes "VERSION" (a string literal of the token VERSION), not the value of VERSION. To stringify the expanded value, use indirect stringification with two levels of macros.
Q.18Hard
What will be the output of:
#define MAX(a,b) ((a)>(b)?(a):(b))
int main() { printf("%d", MAX(5++, 10)); return 0; }
Answer: C
The macro expands to ((5++)>(10)?(5++):(10)). The variable 5++ is evaluated multiple times due to macro substitution, causing undefined behavior. Increment operations in macro arguments should be avoided. This highlights why inline functions or constexpr functions are preferred in modern C++.
Q.19Hard
Which of the following will cause infinite recursion when used?
#define RECURSE() RECURSE()
Answer: C
The C preprocessor does not detect or prevent recursive macro expansion in its definition. RECURSE() will expand to RECURSE() infinitely, causing the preprocessor to hang or run out of memory. Modern compilers have safeguards, but theoretically this creates infinite expansion.
Q.20Hard
What will happen if a macro is defined multiple times with different definitions in the same compilation unit?
#define SIZE 10
#define SIZE 20
Answer: A
Redefining a macro with a different value in the same compilation unit causes a compilation error. To redefine, you must #undef first.