Question
As mentioned in many of my previous questions, I'm working through K&R, and am
currently into the preprocessor. One of the more interesting things —
something I never knew before from any of my prior attempts to learn C — is
the ##
preprocessor operator. According to K&R:
The preprocessor operator
##
provides a way to concatenate actual arguments during macro expansion. If a parameter in the replacement text is adjacent to a##
, the parameter is replaced by the actual argument, the##
and surrounding white space are removed, and the result is re-scanned. For example, the macropaste
concatenates its two arguments:
#define paste(front, back) front ## back
so
paste(name, 1)
creates the tokenname1
.
How and why would someone use this in the real world? What are practical examples of its use, and are there gotchas to consider?
Answer
CrashRpt: Using ## to convert macro multi-byte strings to Unicode
An interesting usage in CrashRpt (crash reporting library) is the following:
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
//Note you need a WIDEN2 so that __DATE__ will evaluate first.
Here they want to use a two-byte string instead of a one-byte-per-char string. This probably looks like it is really pointless, but they do it for a good reason.
std::wstring BuildDate = std::wstring(WIDEN(__DATE__)) + L" " + WIDEN(__TIME__);
They use it with another macro that returns a string with the date and time.
Putting L
next to a __ DATE __
would give you a compiling error.
Windows: Using ## for generic Unicode or multi-byte strings
Windows uses something like the following:
#ifdef _UNICODE
#define _T(x) L ## x
#else
#define _T(x) x
#endif
And _T
is used everywhere in code
Various libraries, using for clean accessor and modifier names:
I've also seen it used in code to define accessors and modifiers:
#define MYLIB_ACCESSOR(name) (Get##name)
#define MYLIB_MODIFIER(name) (Set##name)
Likewise you can use this same method for any other types of clever name creation.
Various libraries, using it to make several variable declarations at once:
#define CREATE_3_VARS(name) name##1, name##2, name##3
int CREATE_3_VARS(myInts);
myInts1 = 13;
myInts2 = 19;
myInts3 = 77;