1
#include <iostream>
void LOG_TRACE() { std::cout << "reach here"; }

#define LOG_LL_TRACE    LOG_TRACE
#define LL_TRACE    0
#define __LOG(level)  LOG_##level()
#define LOG(level) __LOG(##level)

int main()
{
    LOG(LL_TRACE);
    return 0;
}

The code is worked under Visual Studio, but report: test.cpp:13:1: error: pasting "(" and "LL_TRACE" does not give a valid preprocessing token.

How can I fix it?

ps: The macro expansion is supposed to be LOG(LL_TRACE) --> __LOG(LL_TRACE) --> LOG_LL_TRACE().

ps: suppose LL_TRACE must have a 0 value, do not remove it.

Chris Song
  • 159
  • 1
  • 9
  • I don't think I can understand why you would want to do something like this... – Aleks G Sep 27 '11 at 08:25
  • possible duplicate of [Creating C macro with ## and __LINE__ (token concatenation with positioning macro)](http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macro) – littleadv Sep 27 '11 at 08:27
  • The macro expansion is supposed to be LOG(LL_TRACE) --> __LOG(LL_TRACE) --> LOG_LL_TRACE(). __LOG is complex macro in real world, and called by lots LOG macro. – Chris Song Sep 27 '11 at 08:54
  • **Do not use** double underscore. See http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797 – Martin York Sep 27 '11 at 15:15
  • relax Tux-D, it's macro, not a symbol. – Chris Song Sep 28 '11 at 01:21
  • @ChrisSong: What matters is that it's an *identifier*. All identifiers starting with `__` are reserved for all purposes. For example, such an identifier could be an implementation-specific keyword. – Keith Thompson Sep 28 '11 at 01:42
  • `##` concatenates two tokens to form a new token. `LOG_##level` creates a new single identifier, but you can't form a new token from `(` and whatever `level` expands to. They merely need to be adjacent, not joined together. You could even have white-space between them. – Keith Thompson Sep 28 '11 at 01:47

2 Answers2

4

Two things make this code not compile on g++: First, the error you're quoting is because you want to have this:

#define LOG(level) __LOG(level)

Notice no ##. Those hashmarks mean concatenate, but you're not concatenating anything. Just forwarding an argument.

The second error is that you have to remove

#define LL_TRACE    0

This line means you end up calling LOG(0) which expands into LOG_0 which isn't defined.

Adam
  • 16,808
  • 7
  • 52
  • 98
  • The macro expandation should be LOG(LL_TRACE) --> __LOG(LL_TRACE) --> LOG_LL_TRACE(). – Chris Song Sep 27 '11 at 08:46
  • or how to I forward a macro parameter without expansion? – Chris Song Sep 27 '11 at 09:11
  • 1
    Just use the argument, that's how macro expansion works. If you use my definition of LOG then that's exactly what will happen. Just remove that `#define LL_TRACE 0` macro, I've no idea what you're trying to accomplish with it but it's interrupting that sequence: `LOG(LL_TRACE) -> LOG(0) -> __LOG(0) -> LOG_0()` – Adam Sep 27 '11 at 10:44
  • What if I must remain LL_TRACE define? Do macro in gcc have capability to forward argument symbol in macro instead of expand it? – Chris Song Sep 28 '11 at 02:21
  • Now that I look at it, it appears that you want to have multiple levels of logging functions? LL_TRACE being level 0? So just change `#define LOG_LL_TRACE LOG_TRACE` to `#define LOG_0 LOG_TRACE` – Adam Sep 28 '11 at 05:01
1

Shouldn't it be :

#define LOG(level) __LOG(level)

That works:

#include <iostream>
void LOG_TRACE() { std::cout << "reach here"; }
#define LOG_LL_TRACE    LOG_TRACE
#define __LOG( level ) LOG_##level()                                                    
#define LOG(level) __LOG(level)

int main()
{
        LOG( LL_TRACE );                                     
        return 0;                                                           
}
long404
  • 1,037
  • 9
  • 12
  • It doesn't work, it should be LOG(LL_TRACE) --> __LOG(LL_TRACE) --> LOG_LL_TRACE(), not LOG((LL_TRACE)) --> __LOG(0) – Chris Song Sep 27 '11 at 08:49
  • agreed but that is a different issue. My suggestion fixes the error that you pointed out. I edited my post with the behavior you require. – long404 Sep 27 '11 at 08:51
  • Yes, it compiled... But LL_TRACE is a constant that will be used later. e.g. log level filter. – Chris Song Sep 27 '11 at 09:04
  • I'm confused: first you say you want to get LOG_LL_TRACE() at the end, now that you want it to be a constant. In the first case you can filter out logs by defining that macro as "nothing". Isn't it easier to use some of the existing log frameworks? Implementing one is not a trivial task (even though it looks simple). I use google's glog and I'm pretty happy with it. – long404 Sep 27 '11 at 09:35
  • I found a [header only logging libary](https://github.com/andrew-d/cpplog), however it failed to compile under gcc by error that same as question I ask. – Chris Song Sep 27 '11 at 10:08