Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic macros alternative in ANSI C

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);
like image 301
Alex Avatar asked Dec 26 '14 23:12

Alex


2 Answers

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) {
    LOG(("Hello, world\n"));
    int n = 42;
    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.

like image 166
Keith Thompson Avatar answered Oct 18 '22 03:10

Keith Thompson


Here is an even uglier option, but uses single call to printf:

#define PROMPT "[INFO] (%s:%d): "
#define FL __FILE__, LINE__

#define DEBUG0(fmt) printf(PROMPT fmt, FL);
#define DEBUG1(fmt, a1) printf(PROMPT fmt, FL, a1);
#define DEBUG2(fmt, a1, a2) printf(PROMPT fmt, FL, a1, a2);
#define DEBUG3(fmt, a1, a2, a3) printf(PROMPT fmt, FL, a1, a2, a3);

and so on until the most number of arguments that you call the macro with.

like image 5
M.M Avatar answered Oct 18 '22 02:10

M.M