The idea is to define a macro based on printf(). This is a common way to define home made debug/log services.
There are some traps to avoid:
- Do not put a ";" at the end of the macro otherwise you may face
problems when the macro is used in "if/else" statements and you put
a terminating ";" after the macro:
#define test(...) printf(__VA_ARGS__);
int main(void)
{
if (1)
test("message 1\n");
else
test("message 2\n");
return 0;
}
The compiler will display an error like: 'else' without a previous 'if'
So, it is preferable to define the macro without any terminating ";" :
#define test(...) printf(__VA_ARGS__)
- Force the use of the format string otherwise you would get an error in the following:
#define test(...) printf(__VA_ARGS__)
int main(void)
{
char *str = "foo%bar";
test(str);
return 0;
}
The compiler will raise an warning: format not a string literal and no format arguments [-Wformat-security]
because there is a "%" in the string.
So, it is preferable to define the macro as:
#define test(format, ...) printf(format, __VA_ARGS__)
int main(void)
{
char *str = "foo%bar";
test("%s", str);
return 0;
}
- But if you want to print a string without any format specifiers, like :
#define test(format, ...) printf(format, __VA_ARGS__)
int main(void)
{
test("A string without format specifiers\n");
return 0;
}
The compiler will raise an error because the variable part (i.e. __VA_ARGS__
) is empty:
error: expected expression before ')' token
6 | #define test(format, ...) printf(format, __VA_ARGS__)
To prevent this, it is possible to use the preprocessor "##" trick (it is a GCC specific extension):
#define test(format, ...) printf(format, ##__VA_ARGS__)
int main(void)
{
test("A string without format specifiers\n");
return 0;
}
- Of course, as the macro uses a call to a service function (
printf()
), include the corresponding header file (<stdio.h>
) where the macro is defined:
#include <stdio.h>
#define test(format, ...) printf(format, ##__VA_ARGS__)
int main(void)
{
test("A string without format specifiers\n");
return 0;
}
As a conclusion, to avoid all the preceding traps and many others while writing macros in C language, I can advise this Best practices for the C language preprocessor