A case where macros are useful is when you combine them with __FILE__
and __LINE__
.
I have a concrete example in the Bismon software project. In its file cmacros_BM.h
I define
// only used by FATAL_BM macro
extern void fatal_stop_at_BM (const char *, int) __attribute__((noreturn));
#define FATAL_AT_BIS_BM(Fil,Lin,Fmt,...) do { \
fprintf(stderr, "BM FATAL:%s:%d: <%s>\n " Fmt "\n\n", \
Fil, Lin, __func__, ##__VA_ARGS__); \
fatal_stop_at_BM(Fil,Lin); } while(0)
#define FATAL_AT_BM(Fil,Lin,Fmt,...) FATAL_AT_BIS_BM(Fil,Lin,Fmt,##__VA_ARGS__)
#define FATAL_BM(Fmt,...) FATAL_AT_BM(__FILE__,__LINE__,Fmt,##__VA_ARGS__)
and fatal errors are calling something like (example from file user_BM.c
)
FILE *fil = fopen (contributors_filepath_BM, "r+");
if (!fil)
FATAL_BM ("find_contributor_BM cannot open contributors file %s : %m",
contributors_filepath_BM);
When that fopen
fails, the fatal error message shows the source file and line number of that FATAL_BM
macro invocation.
The fatal_stop_at_BM
function is defined in file main_BM.c
Notice also that some of your C files could be generated by programs like GNU bison, GNU m4, ANTLR, SWIG and that preprocessor symbols are also used by GNU autoconf.
Study also the source code of the Linux kernel. It uses macros extensively.
Most importantly, read the documentation of your C compiler (e.g. GCC). Many C compilers can show you the preprocessed form of your C code.
Your
// macro with parameter
#define AREA(l, b) (l * b)
is wrong and should be #define AREA(l, b) ((l) * (b))
if you want AREA(x+2,y-3)
to work as expected.
For performance reasons, you could have defined your function as
inline int area(int a,int b){ return a*b; }
See also: