C Language | Preprocessing | Function-like Macros - #define
A function-like macro accepts parameters and expands arbitrary text through the #define directive. It can resemble a function without introducing function-call overhead because expansion occurs before compilation.
Macro Expansion with Parameters
Functions improve reuse, but even a small function call involves passing arguments and returning control to the caller. For simple calculations, a macro can expand an expression directly at compile time.
#define directive for a function-like macro
#define identifier(argument1, argument2 ...) token-sequence
For example:
#define ADD(a , b) a + b
ADD(10, 20) is replaced with 10 + 20 before compilation.
Code 1
#include <stdio.h>
#define MUL(multiplicand , multiplier) multiplicand * multiplier
int main() {
printf("5 * 5 = %d\n" , MUL(5 , 5));
return 0;
}
Macro expansion is textual, which can cause unexpected operator precedence.
Code 2
#include <stdio.h>
#define MUL(multiplicand , multiplier) multiplicand * multiplier
int mul(int multiplicand , int multiplier) {
return multiplicand * multiplier;
}
int main() {
printf("macro: MUL(3 + 2 , 5) = %d\n" , MUL(3 + 2 , 5));
printf("function: mul(3 + 2 , 5) = %d\n" , mul(3 + 2 , 5));
return 0;
}
The regular function returns 25, but the macro expands to 3 + 2 * 5 and returns 13. Protect each argument and the entire expression with parentheses:
#define MUL(multiplicand , multiplier) ((multiplicand) * (multiplier))
Macros are useful for concise bit operations.
Code 3
#include <stdio.h>
typedef unsigned char BYTE;
#define RGB(r , g , b) ((BYTE)(r) << 16) | ((BYTE)(g) << 8) | (BYTE)(b)
#define RED(color) (BYTE)((color) >> 16)
#define GREEN(color) (BYTE)((color) >> 8)
#define BLUE(color) (BYTE)(color)
int main() {
int color = RGB(0xFF , 0xEE , 0xAA);
printf("R = %X : G = %X : B = %X\n" ,
RED(color) , GREEN(color) , BLUE(color));
return 0;
}
This example stores red, green, and blue components in one integer and extracts each byte with a macro. Function-like macros are commonly used for small transformations and for wrapping repetitive calls, but their textual expansion must always be considered.