How do #define macros work (object-like and function-like)?
The #define directive creates macros -- text substitutions performed by the preprocessor before compilation.
Object-like macros (constants):
#define PI 3.14159
#define MAX_SIZE 100
Every occurrence of PI is replaced with 3.14159.
Function-like macros (parameterized):
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
They look like functions but are text substitution. The parentheses around parameters and the entire expression are critical to avoid operator precedence bugs.
Key differences from functions:
- No type checking.
- No function call overhead.
- Arguments are substituted textually, not evaluated once.
- Can work with any type (type-generic).
- Side effects in arguments can be evaluated multiple times.
Object-like: #define NAME replacement_text
Function-like: #define NAME(params) replacement_text
#define PI 3.14159 // constant
#define SQUARE(x) ((x)*(x)) // function-like
Parenthesize:
- Each parameter: (x)
- Entire expression: ((x)*(x))
Text substitution, NOT function call
No type checking, no call overhead
#include <stdio.h>
/* Object-like macros */
#define PI 3.14159
#define MAX_BUF 256
#define DEBUG 1
/* Function-like macros (with proper parenthesization) */
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(x) ((x) >= 0 ? (x) : -(x))
/* Multi-line macro */
#define SWAP(a, b, type) do { \
type _tmp = (a); \
(a) = (b); \
(b) = _tmp; \
} while (0)
int main(void) {
printf("PI = %f\n", PI); /* 3.141590 */
printf("SQUARE(5) = %d\n", SQUARE(5)); /* 25 */
printf("MAX(3, 7) = %d\n", MAX(3, 7)); /* 7 */
/* Works with any type */
printf("MAX(3.5, 2.1) = %f\n", MAX(3.5, 2.1)); /* 3.5 */
/* do-while(0) pattern for multi-statement macros */
int x = 10, y = 20;
SWAP(x, y, int);
printf("x=%d y=%d\n", x, y); /* x=20 y=10 */
#if DEBUG
printf("Debug mode is on\n");
#endif
return 0;
}
- •Object-like macros are constants; function-like macros are parameterized
- •Always parenthesize macro parameters AND the entire expression
- •Macros are text substitution -- no type checking, no call overhead
- •Use do { ... } while(0) for multi-statement macros
- •Backslash \ continues a macro definition to the next line
- •SQUARE(x+1) without parens becomes x+1*x+1 = 2x+1, not (x+1)^2
- •SQUARE(i++) evaluates i++ twice: ((i++)*(i++)) -- double increment!
- •Macros have no scope -- they persist until #undef or end of translation unit
- •#define MAX(a,b) has NO space between MAX and ( -- space makes it object-like