Macro Without Space
Asked Answered
C

2

7

I have a macro I use for debugging.

#define diagnostic_arg(message,...) fprintf(stderr,message,__VA_ARGS__)

I've found that I need to use wide-chars in my program, so I would like to change just my macro and have everything work:

#define diagnostic_arg(message,...) fwprintf(stderr,message,__VA_ARGS__)

However, I need wide character strings, which are defined by putting an L in front of the string's beginning quote mark:

#define diagnostic_arg(message,...) fprintf(stderr,Lmessage,__VA_ARGS__)

Now obviously, the above line doesn't work. But if I use L message, that won't work either. So how do I write Lmessage and have it do what I would like?

Cadaver answered 21/3, 2012 at 21:18 Comment(0)
L
16

You can use the token pasting operator ##:

#define diagnostic_arg(message,...) fprintf(stderr,L##message,__VA_ARGS__)

However, it might be better to use TEXT macro (if you are in Visual Studio) which will do the right thing whether UNICODE is defined or not:

#define diagnostic_arg(message,...) fprintf(stderr,TEXT(message),__VA_ARGS__)

If you're not, TEXT can be defined like this:

#ifdef UNICODE
#define TEXT(str) L##str
#else
#define TEXT(str) str
#endif

However, if you plan on using other #defines as the first argument to this macro (and really even if you don't plan on it), you will need another layer of indirection in the macro so the definition will be evaluated instead of pasted together with L as text. See Mooing Duck's answer for how to do that, his is actually the correct way to do this, but I'm not deleting this answer because I want to keep my 80 rep.

Latreshia answered 21/3, 2012 at 21:20 Comment(3)
Just realize that the TEXT() macro is a Microsoft thing - I don't think it's as common in the non-Windows world (but maybe I'm wrong). In any case, it's easy enough to implement yourself.Sacrificial
@MichaelBurr I thought the L is also Microsoft thing, no?Latreshia
@Seth: Nope, the L prefix is standard C and C++. It creates a literal of type wchar_t[].Richellericher
M
8

I vaguely recall the answer being something along the lines of

//glues two symbols together that can't be together
#define glue2(x,y) x##y
#define glue(x,y) glue2(x,y) 
//widens a string literal
#define widen(x) glue(L,x)

#define diagnostic_arg(message,...) fprintf(stderr,widen(message),__VA_ARGS__)

Glue sometimes needs to be two macros (as I've shown), for bizzare reasons I don't quite understand, explained at the C++faq

Mile answered 21/3, 2012 at 21:21 Comment(5)
Of course, Seth Carnegie's answer is far more straight to the point, I don't know why the direct route didn't occur to me.Mile
I remember something like this too, I can't remember when it's needed though.Latreshia
Ah, here it is: parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 It's so you can use other #defines in there. This answer is actually the correct one.Latreshia
You need the extra bit of indirection in case what's passed in the message argument is a macro itself.Sacrificial
I appreciate the technical correctness of this. @SethCarnegie's answer seemed to work fine in my use scenario, though. Thank you both.Cadaver

© 2022 - 2024 — McMap. All rights reserved.