C Programming Tricky Questions
Tricky Questions on Preprocessor Directives
What is the difference between preprocessor and compiler?
The preprocessor processes source code before compilation. It handles directives starting with #. The compiler translates preprocessed code to machine code. Preprocessor works at text level, compiler at syntax/semantic level.
What is the difference between #include "file.h" and #include <file.h>?
#include "file.h" searches current directory first, then system directories. #include <file.h> searches system directories only. Use quotes for user headers, angle brackets for system/library headers.
Tricky Point: The search order can be modified by compiler options and environment variables like -I and INCLUDE.
What is the difference between #define macro and const variable?
#define is preprocessor text substitution (no type checking, no memory allocation). const is compile-time variable (type checking, occupies memory). Macros can't be debugged easily, const variables can.
What is macro expansion and when does it happen?
Macro expansion replaces macro names with their definitions. Happens during preprocessing, before compilation. It's pure text substitution, no evaluation of expressions.
What are predefined macros and what are some common ones?
Predefined macros are set by compiler. Common ones: __FILE__ (current filename), __LINE__ (current line number), __DATE__, __TIME__, __STDC__ (Standard C compliance).
What is the purpose of #ifdef, #ifndef, and #endif?
Conditional compilation directives. #ifdef checks if macro is defined. #ifndef checks if macro is NOT defined. #endif ends conditional block. Used for platform-specific code, debugging, feature flags.
What is token pasting operator (##) and stringizing operator (#)?
## concatenates tokens during macro expansion. # converts macro argument to string literal. Example: #define STR(x) #x makes STR(hello) → "hello". ## joins tokens: CONCAT(a, b) → ab.
What is the difference between #if and #ifdef?
#if evaluates constant expression (can use defined() operator). #ifdef checks only if macro is defined. #if is more flexible, #ifdef is simpler for existence checks.
What is macro recursion and is it allowed?
Macro recursion (macro expanding to itself) is NOT allowed. Preprocessor detects and stops infinite recursion. However, mutual recursion between macros may work until depth limit.
What is the purpose of #pragma directive?
#pragma provides compiler-specific instructions. Implementation-defined behavior. Common pragmas: #pragma once (header guard), #pragma pack (alignment), #pragma warning (disable warnings).
What is header guard and why is it important?
Header guard prevents multiple inclusion of same header. Typically: #ifndef HEADER_NAME, #define HEADER_NAME, ... #endif. Without it, duplicate definitions cause compilation errors.
What is the difference between #define and #undef?
#define creates/redefines macro. #undef removes macro definition. Useful for temporarily disabling macros or ensuring clean state before testing #ifdef.
What is function-like macro and what are its pitfalls?
Macro that looks like function: #define SQUARE(x) ((x)*(x)). Pitfalls: multiple evaluation of arguments, operator precedence issues, side effects. Always parenthesize arguments and whole expression.
Warning: SQUARE(x++) increments x twice due to macro expansion!
What is the ## operator pitfall with empty arguments?
When ## concatenates tokens and argument is empty, behavior undefined in C89/C90, but C99 specifies empty token is removed. Example: #define CONCAT(a,b) a##b, CONCAT(x,) may not work as expected.
What is #line directive and when is it used?
#line changes line number and filename reported by __LINE__ and __FILE__. Used by code generators (lex/yacc) to map errors to original source, not generated code.
What is the difference between #error and #warning?
#error causes compilation to stop with error message. #warning (GCC/Clang extension) emits warning but continues compilation. Both useful for conditional compilation checks.
What is variadic macro and how is it declared?
Macro with variable arguments: #define PRINT(...) printf(__VA_ARGS__). Use ... for arguments, __VA_ARGS__ in expansion. C99 feature, useful for logging/debug macros.
What is macro redefinition and when is it allowed?
Redefining macro with same definition is allowed (ignored). Redefining with different definition causes warning/error. Use #undef first to avoid warnings.
What is the purpose of # and ## in macro arguments?
# before parameter stringizes it. ## between parameters concatenates them. Both are preprocessor operators, not runtime. They work only in macro definitions.
What is translation unit and how does preprocessor affect it?
Translation unit is source file after preprocessing (all #includes expanded, macros substituted). Preprocessor creates single translation unit from .c file and all included headers.
What is the difference between #if defined(X) and #ifdef X?
Both check if X is defined. #if defined(X) can be combined with logical operators: #if defined(X) && defined(Y). #ifdef is simpler but less flexible.
What is the significance of backslash at end of macro definition?
Backslash (\) continues macro definition to next line. Allows multi-line macros. Must be last character on line (no trailing spaces).
What is the difference between #pragma once and header guards?
Both prevent multiple inclusion. #pragma once is compiler extension (not standard), simpler, potentially faster. Header guards are standard, work everywhere, but prone to typos.
What is macro argument prescan and why is it important?
Arguments are expanded before substitution into macro body, unless operand is # or ##. Important for nested macros: #define STR(x) #x, STR(__LINE__) expands to "__LINE__" not line number.
What is the difference between C preprocessor and C++ constexpr?
Preprocessor works at text level (C and C++). constexpr (C++11) evaluates at compile time with type safety. constexpr is preferred in C++ for compile-time computations, preprocessor for conditional compilation.
Tricky Point: While constexpr replaces many macro uses in C++, preprocessor is still needed for conditional compilation and include guards in both languages.
Note: These tricky questions cover important concepts about preprocessor directives in C, including macro expansion, conditional compilation, and common pitfalls. Understanding the preprocessor is crucial for writing portable and maintainable code.