Question

what I'd like to do (for logging purposes) is something like this:

This code has been written to show my problem, actual code is complex and yes, I have good reasons to use macros even on C++ =)

# define LIB_SOME 1
# define LIB_OTHER 2

# define WHERE "at file #a, line #l, function #f: "
// (look for syntax hightlighting error at SO xd)
# define LOG_ERROR_SIMPLE(ptr, lib, str) ptr->log ("ERROR " str \
                                                   " at library " #lib);
# define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, lib, WHERE str)

LOG_ERROR_SIMPLE (this, LIB_SOME, "doing something")
LOG_ERROR (this, LIB_OTHER, "doing something else")

LOG_ERROR_SIMPLE() writes the stringification of the lib parameter (a macro name surrounded by " ")

but then LOG_ERROR writes the stringification of the macro already expanded ("2"). this is expected, since lib got its expansion before expanding and calling LOG_ERROR_SIMPLE. but this is not what I need.

Basically my question is this: how to avoid macro expansion of a macro function parameter when calling another macro function?

There is a trick I use that avoids macro expansion:

  LOG_ERROR(ptr, lib, str, x) LOG_ERROR_SIMPLE(ptr, x##lib, WHERE str)

  LOG_ERROR(this, LIB_OTHER, "some error",)

(pasting x and lib produces LIB_OTHER and this value is used to call LOG_ERROR_SIMPLE, its not macro expanded before that call)

There is some way to obtain this same behaviour without using a trick?

Was it helpful?

Solution

I'm doing:

#include <cstdio>

#define FOO 1
#define BAR 2

#define LOG_SIMPLE(ptr, lib, str) printf("%s\n", #lib);
#define LOG(ptr, lib, str) LOG_SIMPLE(ptr, ##lib, str)

int main()
{
  LOG_SIMPLE(0, FOO, "some error");
  LOG(0, BAR, "some other error");
}

which prints out:

FOO
BAR

Works with MSVC2005 but not with gcc/g++.


EDIT: to make it work with gcc/g++ you can abuse variadic macros:

#include <stdio.h>

#define FOO 1
#define BAR 2

#define LOG_SIMPLE(ptr, str, lib) printf("%s\n", #lib);
#define LOG(ptr, str, lib, ...) LOG_SIMPLE(ptr, str, lib##__VA_ARGS__)

int main()
{
  LOG_SIMPLE(0, "some error", FOO);
  LOG(0, "some other error", BAR);
  LOG(0, "some other error", FOO, BAR);
}

However, it's your discipline not to use the macro with too many parameters. MSVC2005 prints out

FOO
BAR
FOO2

while gcc prints out

FOO
BAR
FOOBAR

OTHER TIPS

If you don't need the expanded lib aliases (i.e. '1' & '2') in your cpp macros, you could also use an enum instead of defined values.

I don't think you can. What you could do, though, is add a layer of macro for it to unpeel in its place:

#define WRAP(x) x
#define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, lib, WHERE WRAP(str))

You almost had it. Use

#define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, ##lib, WHERE str)

On gcc
LOG_ERROR(this, LIB_OTHER, "some error")
yields
this->log ("ERROR " "at file #a, line #l, function #f: " "some error" " at library " "LIB_OTHER");

I would also remove the trailing ';' from your macro so that your code would look like:
LOG_ERROR(this, LIB_OTHER, "some error");

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top