The blog introduces macros in C.

Object-like Macros
In the first article, I briefly mentioned an alternative method of defining a constant, #define
, which is an example
of object-like macros.
# define PI 3.14
int main() {
int radius = 2;
printf("Area: %.3f\n", radius*radius*PI); // => Area: 12.560
return 0;
}
As I discussed before, the preprocessor will replace all occurrences of the macro “PI” with 3.14 before compilation. Macros are a way of creating a constant without explicit type declaration, which is not usually considered good practice but is sometimes necessary.
Function-like Macros
In addition to defining a constant with macros, you can also define a function* using macros like the following:
# define PI 3.14
# define area(r) r*r*3.14
int main() {
int radius = 2;
printf("Area: %.3f\n", area(radius)); // => Area: 12.560
double dRadius = 2.5;
printf("Area: %.3f\n", area(dRadius)); // => Area: 19.625
return 0;
}
Just as object-like macros do not care about types, function-like macros also do not care about input types. Since macros are just text replacements, they do not have to store input parameters in memory like a normal function. Function-like macros can also take multiple arguments:
# define findMax(array, length) ({ \
typeof(array[0]) curMax = array[0]; \
for (int i = 0; i < length; i++) { \
if (array[i] > curMax) { \
curMax = array[i]; \
} \
} \
curMax; \
})
int main() {
int array1[4] = {5,7,9,1};
printf("Max: %d\n", findMax(array1, 4)); // => Max: 9
double array2[4] = {0.33, 1.94, 8.34, 3.14};
printf("Max: %.2f\n", findMax(array2, 4)); // => Max: 8.34
return 0;
}
When using macros, we need to be careful that they do not have return statements, as macros are just text replacements.
Conditional Compilation Directives
When we want to use certain functions only for debugging, we can define a DEBUG_MODE
object-like macro that can take a
value of either 0 or 1, and use conditional compilation directives like the following:
# define DEBUG_MODE 1
int main() {
#if DEBUG_MODE == 1
printf("DEBUG_MODE! \n");
#elif DEBUG_MODE == 0
printf("NOT DEBUG_MODE! \n");
#else
printf("???\n");
#endif
return 0;
}
You can also use defined()
, #ifdef
, or #ifndef
to check if object-like macro named DEBUG_MODE
is defined or not.
# define DEBUG_MODE
int main() {
#if defined(DEBUG_MODE)
printf("DEBUG_MODE! \n");
#endif
#ifdef DEBUG_MODE
printf("DEBUG_MODE! \n");
#else
printf("NOT DEBUG_MODE! \n");
#endif
#ifndef DEBUG_MODE
printf("NOT DEBUG_MODE! \n");
#endif
return 0;
}
The above approach is simpler than allowing DEBUG_MODE
to take on specific values. Conditional compilation directives can
also be used to set different values to object-like macros depending on conditions.
Exercises
From this article, there will be an exercise section where you can test your understanding of the material introduced in the article. I highly recommend solving these questions by yourself after reading the main part of the article. You can click on each question to see its answer.
Resources
- Portfolio Courses. 2022. Function-like Macros | C Programming Tutorial. YouTube.
- Portfolio Courses. 2022. #if #elif #else Conditional Compilation Directives | C Programming Tutorial. YouTube.
- Portfolio Courses. 2022. #ifdef #ifndef Conditional Compilation Directives | C Programming Tutorial. YouTube.