I know that variadic macros have been added in C99 (and via GNU extensions). I've been wondering if there is a nice alternative in ANSI C.
I've come up with something like this, but it's still kind of awkward:
void log_info(const char *file, int line, const char *fmt, ...)
{
#ifdef DEBUG
va_list ap;
char newfmt[1024] = { 0 };
va_start(ap, fmt);
sprintf(newfmt, "[INFO] (%s:%d): %s\n", file, line, fmt);
vfprintf(stderr, newfmt, ap);
va_end(ap);
#endif
}
So that this can be called like this:
log_info(__FILE__, __LINE__, "info message: %s %d", "helloworld", 12);
There is nothing wrong with this approach, however I'm wondering if there is a nicer way of doing it? Eg. with no need to specify file/line everytime.
I'd appreciate any feedback. :)
Edit: By ANSI C here I mean C89.
Edit: The answer below is fine but I believe given it requires running the printing command twise it may impose some thread-safety issues as it is. Another alternative might be to use define to minimize the typing (also quite ugly):
#define __FL__ __FILE__, __LINE__
and then run the command like:
log_info(__FL__, "info message: %s %d", "helloworld", 12);
It's a little ugly, but a sequence of comma-separated expressions in parentheses can be treated as a single argument.
An example:
#include <stdio.h>
#define LOG(args) (printf("LOG: %s:%d ", __FILE__, __LINE__), printf args)
int main(void) {
int n = 42;
LOG(("Hello, world\n"));
LOG(("n = %d\n", n));
return 0;
}
The output:
LOG: c.c:6 Hello, world
LOG: c.c:8 n = 42
Note that this requires an extra set of parentheses in the call.
The preprocessed code will look like:
#include <stdio.h>
int main(void)
{
int n = 42;
(printf("LOG: %s:%d ", "test_variadic.c", 7), printf ("Hello, world\n"));
(printf("LOG: %s:%d ", "test_variadic.c", 9), printf ("n = %d\n", n));
return 0;
}