Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
364 views
in Technique[技术] by (71.8m points)

c++ - Token pasting and __LINE__

I'm writing a simple macro to show TRACE information.

This is what I'm using ,

#ifdef __DEBUG__
#define TRACE  { PrintErrorMsg("Trace exception at " __FILE__  "LineNo:"##(__LINE__) "Function: " __FUNCTION__ " " );}
#else 
#define TRACE 
#endif

This is working with FILE, but it doesn't seems to work with LINE , Any idea how could I deal with this. I already tried stringing operator too.Which is as bellow.

#ifdef __DEBUG__
#define TRACE  { PrintErrorMsg("Trace exception at " __FILE__  "LineNo:"#(__LINE__) "Function: " __FUNCTION__ " " );}
#else 
#define TRACE 
#endif

and without parms and with double parms , ex - __LINE__ or ((__LINE__)) Any idea how could I deal with this problem?

And I come up with this,

#ifdef __DEBUG__
#define ERROR_MSG_BUF_SIZE 1024
#define TRACE  { char * error_msg_buffer = new char[ERROR_MSG_BUF_SIZE]; 
                 sprintf(error_msg_buffer,"Trace Exception at file: %s ,Line : %d , Function %s 
",__FILE__,__LINE__,__FUNCTION__);
PrintErrorMsg(error_msg_buffer );
delete[] error_msg_buffer;}
#else 
#define TRACE 

But I want to do it without using sprintf , just only by stringing and token pasting. Any idea?

#endif

--Thanks in advance--

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When you try to stringize something with #x, that x must be a macro parameter:

#define FOO #__LINE__ /* this is not okay */
#define BAR(x) #x     /* this is okay */

But you cannot simply say BAR(__LINE__), because this will pass the token __LINE__ into BAR, where it is immediately turned into a string without expansion (this is by design), giving "__LINE__". The same thing happens with the token-pasting operator ##: expansion of their operands never happens.

The solution is to add indirection. You should always have these in your codebase somewhere:

#define STRINGIZE(x) STRINGIZE_SIMPLE(x)
#define STRINGIZE_SIMPLE(x) #x

#define CONCAT(first, second) CONCAT_SIMPLE(first, second)
#define CONCAT_SIMPLE(first, second) first ## second

Now STRINGIZE(__LINE__) turns to STRINGIZE_SIMPLE(__LINE__) which gets fully expanded to (for example) #123, which results in "123". Phew! I leave STRINGIZE_SIMPLE around on the off chance I want the original behavior. So your code would be something like:

#include <iostream>

#define STRINGIZE(x) STRINGIZE_SIMPLE(x)
#define STRINGIZE_SIMPLE(x) #x

#define TRACE()                                                 
        PrintErrorMsg("Trace exception in " __FILE__            
                      " at line number " STRINGIZE(__LINE__)    
                      " in function " __FUNCTION__ ".")

void PrintErrorMsg(const char* str)
{
    std::cout << str << std::endl;
}

int main()
{
    TRACE();
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...