1

I'm trying to write a macro to simplify the use of LOG4CPLUS. But I got some trouble when writing the macro.

This is something in my cpp file:

Logger logger = Logger::getInstance("ManagerServer");

After that, I can log one line like this:

LOG4CPLUS_ERROR(logger, logEvent);

I just want to write a macro, than I can change logEvent to some variable argument. And Use like this:

LogErr("failed");
LogErr("failed times %d", iTimes);

So, I write like this:

#define LogErr(fmt, args...)\
    do {\
        char szBuf[MAX_LOG_BUFFER_SIZE];\
        memset(szBuf, 0, MAX_LOG_BUFFER_SIZE);  \
        vsnprintf(szBuf, MAX_LOG_BUFFER_SIZE, fmt, ##args); \
        LOG4CPLUS_ERROR(logger, szBuf);\
    } while(0)

But when I compile. g++ give me this message:

error: expected primary-expression before ')' token

Does any one can help me? I really appreciate it.

wilx
  • 17,697
  • 6
  • 59
  • 114
Eric guan
  • 333
  • 1
  • 3
  • 5
  • 1
    In C, if you provide a name for a macro argument (`args`) you can't invoke that macro without supplying the argument (`LogErr("failed");`). If you don't name the argument, you can't use it inside the macro expansion. Try a honest to god function instead. – pmg Jun 25 '11 at 13:41
  • 1
    It's called a **macro**, not a micro, and I doubt that one can create a macro with variable number of arguments – Armen Tsirunyan Jun 25 '11 at 13:42
  • 1
    Writing multi-language source files is hard. I suggest you stick to only one of C or C++ – pmg Jun 25 '11 at 13:43
  • Why did you say `##args` and not just `args`? – Kerrek SB Jun 25 '11 at 13:52
  • Possibly typo? I presume you mean `snprintf`(not `vsnprintf`). – Ise Wisteria Jun 25 '11 at 14:30

4 Answers4

2

Oops ... C tag has been removed

The problem is with the expansion of the macro when not enough parameters are supplied (LogErr("failed")). That does not work in C.

Try adding a dummy parameter

LogErr("failed", 0);
/* or better */
LogErr("%s", "failed");

Also you cannot use v* functions inside a macro like you're trying to: the preprocessor does not know about variable arguments ad can't create objects of type va_list.


In C99, one way to do what it appears you're trying to do is

#include <stdio.h>
#include <string.h>

#define MAX_LOG_BUFFER_SIZE 100

#define LogErr(fmt, ...)                                      \
  do {                                                        \
    char szBuf[MAX_LOG_BUFFER_SIZE];                          \
    memset(szBuf, 0, MAX_LOG_BUFFER_SIZE);                    \
    snprintf(szBuf, MAX_LOG_BUFFER_SIZE, fmt, ##__VA_ARGS__); \
    /* LOG4CPLUS_ERROR(logger, szBuf); */                     \
  } while(0)

int main(void) {
  LogErr("err %d", 4);
  /*LogErr("failed");*/
  LogErr("%s", "failed");
  return 0;
}

Note: snprintf and ##__VA_ARGS

pmg
  • 106,608
  • 13
  • 126
  • 198
1

You're missing a comma after the args parameter.

#define LogErr(fmt, args, ...)\
                        ^

Also, I don't know if g++ currently supports variadic macros, it's a C++11 feature. (I believe the C compiler supports them, though).

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
1

Thanks to pmg, Ferruccio and all of you. You guys really saved me!

These code just run well on my pc. It seems like I did miss up the vsnprintf and snprintf.

#define Log(fmt, args...) \
    do {\
        char szBuf[MAX_LOG_BUFFER_SIZE];\
        snprintf(szBuf, MAX_LOG_BUFFER_SIZE-1, fmt, ##args);\
        LOG4CPLUS_ERROR(logger, szBuf);\
    } while(0)

int main() {
    Log("Hello macro.");
    Log("Hello macro %d", 1);
    Log("Hello macro %s, %d", "foo", 2);

    return 0;
}

Thanks again!

MindGeek
  • 9
  • 1
0

Recent (1.1.0+) version of Log4cplus do support logging using printf-style macros. Your example in OP would look like this:

LOG4CPLUS_ERROR_FMT(logger, "failed");
LOG4CPLUS_ERROR_FMT(logger, "failed times %d", iTimes);

See loggingmacros.h for implementation details if you still want to reimplement it differently.

wilx
  • 17,697
  • 6
  • 59
  • 114