Beyond efficiency, macros can still have an edge: they allow some form of meta-programming - making the end code easier to write and to look at, while strictly using functions would not allow some particular syntax or way to manipulate objects and constants. Sometimes a good macro is way nicer to handle than having to go through hoops with functions.
Yes, definitely. Even I have shown examples here from generics to basic polymorphism to expanding macros differently based on the number of arguments, all to make it easier for the programmer to implement useful things, without compromising the efficiency of the compiled code.
Macros are an useful tool, but they have their limitations. It is using macros where something else works better that I referred to as "fetishism".
(I find myself using the "when the only tool you have is a hammer, all problems look like nails" idiom too often, so I tried something else for once.)
Have a look at my use of macros in https://github.com/brucehoult/trv and tell me if you think it's disgusting or not :-)
Not disgusting, just standard way of using the preprocessor for polymorphism, in my opinion. And very clean implementation, too.
I myself posted a much more "disgusting-looking", but perfectly useful example of this kind of polymorphism,
six months ago in the Embedded programming sub-board (Concurrency in a bare metal environment thread).
The most annoying deficiency with the C preprocessor is that no string operations or matching is supported in preprocessor directives. You can compare and do basic arithmetic with integers, but basically nothing with strings. To me, it is a good reminder of the limitations of the preprocessor.
One of the most common ways I use macros is default constants that are trivial to override at compile time:
#ifndef DEFAULT_VALUE #define DEFAULT_VALUE 42 #endifYou see, if using GCC/Clang/Intel CC, you just add a cimpile option, say
-DDEFAULT_VALUE=99, to override the default.
Another common use case is with preprocessor arithmetic, when I want to treat an undefined macro as a zero, and generate different code based on the macro value:
#if VALUE-0 == 0 printf("Value is zero or undefined\n"); #elif VALUE-0 == 1 printf("Value is one\n"); #else printf("Value is defined, but neither one nor zero.\n"); #endifWhen used in a
preprocessor arithmetic expression, undefined macros are empty. So, if
VALUE is undefined, the preprocessor sees
VALUE-0 as
-0 which is the same as zero.
This can be a bit confusing, because if you use
VALUE in the C code, and it is not defined as a macro, it is then treated as
VALUE (i.e., a normal identifier). It's kinda-sorta the opposite behaviour between the preprocessor and the compiler proper, really. But useful, nevertheless.