The following (test with gcc -E blah.c):
#define UNUSED(type) type UNUSED_ ## __COUNTER__
UNUSED(char const *)
UNUSED(int)
Generates:
char const * UNUSED__COUNTER__
int UNUSED__COUNTER__
I'm expecting:
char const * UNUSED0
int UNUSED1
I've tried calling another macro, wrapping the arguments in brackets to no avail.
If I don't paste the tokens it seems to work fine.
The documentation specifically mentions the use of __COUNTER__ in token pasting.
What am I doing wrong?
Experimenting with gcc 4.4, this works:
#define UNUSED(type) UNUSED_(type, __COUNTER__)
#define UNUSED_(type, counter) UNUSED__(type, counter)
#define UNUSED__(type, counter) type UNUSED_ ## counter
UNUSED(char const *)
UNUSED(int)
But it doesn't work if I take out even one level of intermediates.
__COUNTER__ was only introduced in GCC 4.3 - if you happen to use an earlier version, the macro is simply not defined. In that case Boost.PPs BOOST_PP_COUNTER macro might be worth looking into.
On newer GCC versions you still need a different approach to concatenation, as ## prevents its arguments from expanding. Thus you have to expand them first before using ##:
#define CAT(a, b) CAT_I(a, b)
#define CAT_I(a, b) CAT_II(a ## b)
#define CAT_II(x) x
#define UNUSED(type) type CAT(UNUSED_, __COUNTER__)
If you're already using Boost, BOOST_PP_CAT() gives you the same functionality.
I believe you must "double expand" it:
#define STR(x) #x
#define UNUSED(type) type UNUSED_ ## STR(__COUNTER__)
UNUSED(char const *)
UNUSED(int)
Related
I am curious if any of you can think of a way upon macro expansion to repeat the macro itself. Here is an incredibly small scale version of an overall bigger problem:
#include<stdio.h>
#define LETTERS\
X(A)\
X(B)\
X(C)\
X(D)
#define X(L) #L
int main(int nargs,char** args)
{
printf("%s\n",LETTERS);
return 0;
}
Output: ABCD
Desired output: AABCD BABCD CABCD DABCD
The desired output is clearly similar to a nested (N^2) loop over whatever input data.
The stringification doesn't matter, it's only there for compilation.
There are some obvious and some not so obvious solutions to the desired output.
One is to make a complete copy of the macro, then between each X element, you simply refer to the copy. This would be wasteful and I don't want to do it. Obviously you can't refer to the macro itself due to recursion. I have made many attempts to find a decent solution, and won't list all of them as it would take up way too much time. I am open to solutions that use other macros to repeat or expand the original, or solutions that use janky forms of recursion.
#include<stdio.h>
#define LETTERS_COPY\
X(A)\
X(B)\
X(C)\
X(D)
#define LETTERS\
X(A)\
LETTERS_COPY\
X(B)\
LETTERS_COPY\
X(C)\
LETTERS_COPY\
X(D)\
LETTERS_COPY
#define X(L) #L
int main(int nargs,char** args)
{
printf("%s\n",LETTERS);
return 0;
}
Again, this builds just fine and works, but requires a complete duplicate of the original data, interjecting itself between each X element.
If you use an iterating macro, like how one is defined in the P99 macro utility collection, then it becomes much easier to solve.
Since we intend to define an iterating macro, we don't need X-macros on the letters anymore.
#define LETTERS \
A \
,B \
,C \
,D
Below is a simplified iterating macro that supports up to 5 arguments. Hopefully you see how to extend the implementation if you need more.
#define XX(X, ...) \
XX_X(__VA_ARGS__, XX_5, XX_4, XX_3, XX_2, XX_1) \
(X, __VA_ARGS__)
#define XX_X(_1,_2,_3,_4,_5,X,...) X
#define XX_1(X, _) X(_)
#define XX_2(X, _, ...) X(_) XX_1(X, __VA_ARGS__)
#define XX_3(X, _, ...) X(_) XX_2(X, __VA_ARGS__)
#define XX_4(X, _, ...) X(_) XX_3(X, __VA_ARGS__)
#define XX_5(X, _, ...) X(_) XX_4(X, __VA_ARGS__)
So, if you invoke XX(X, LETTERS), it will expand into the X-macro version of LETTERS you had before.
The magic of the XX() macro is the meta nature of the XX_X() macro, which selects the right numeric macro to use. The numeric macro is passed in reverse order to the XX_X() macro when it is invoked by XX(). This makes it so that XX_X() selects a lower numeric macro if __VA_ARGS__ contains fewer arguments.
Now, we create a macro to turn the argument into a string:
#define STR(X) STR_(X)
#define STR_(X) #X
This allows you to easily create the string with all your letters.
And printing your iterative output just needs another macro.
int main () {
const char *letters = XX(STR, LETTERS);
#define LETTERS_PRINT(X) printf("%s%s\n", #X, letters);
XX(LETTERS_PRINT, LETTERS)
}
We see that the solution applies XX() twice. Once to create the string of all your letters. Once to create the output, which is prepending each letter to the combined letters.
Try it online!
For anyone wondering, the best I could do was make a second X macro that takes 2 args, and the outer list becomes a function macro that takes a single arg. This lets you pass data to the list, and to the second x macro, while still being able to unpack either X macro however you like.
#include<stdio.h>
#define _CAT(A,B) A##B
#define CAT(A,B) _CAT(A,B)
#define _STR(S) #S
#define STR(S) _STR(S)
#define LETTERS(L)\
XX(L,X(A))\
XX(L,X(B))\
XX(L,X(C))\
XX(L,X(D))
int main(int nargs,char** args)
{
#define X(L) L
#define XX(L1,L2) STR(CAT(L1,L2))
printf("%s\n",LETTERS(A));
printf("%s\n",LETTERS(B));
printf("%s\n",LETTERS(C));
printf("%s\n",LETTERS(D));
#undef XX
#undef X
return 0;
}
How to fix the macro expansion issue below ?
#define GET_VAL 3,2
#define ADD_VAL(val0, val1) ((val0) + (val1))
void foo()
{
int res = ADD_VAL(GET_VAL);
}
The macro is getting expanded as below and resulting in an error. I am using MSVC 2019
res = 3,2 + ;
I even tried using a helper macro as below, but still getting the same error.
#define GET_VAL 3,2
#define ADD_VAL1(val0, val1) (val0 + val1)
#define ADD_VAL(val) ADD_VAL1(val)
Expecting expansion:
ADD_VAL(GET_VAL); --> ADD_VAL(3, 2); --> 3 + 2
By default msvc doesn't use a standard confirming preprocessor implementation, make sure to enable it with /Zc:preprocessor
Macros fully expand their arguments in isolation before pasting them into the replacement text, but the resulting tokens aren't separated into a new argument list. They way to fix your behavior is to create an intermediate macro that expands the arguments, and passes the expanded arguments to your macro:
#define GET_VAL 1,2
#define ADD_VAL(...) ADD_VAL_(__VA_ARGS__)
#define ADD_VAL_(a,b) ((a)+(b))
ADD_VAL(GET_VAL) // should work now
Another option is to write a fx macro that evaluates arguments and applies a function to them:
#define FX(f,...) f(__VA_ARGS__)
#define ADD_VAL(a,b) ((a)+(b))
FX(ADD_VAL,GET_VAL) // should work now
C preprocessor can be abused in horrible ways
#define GET_VAL 3,2
// #define ADD_VAL(val0, val1) ((val0) + (val1))
#define ADD_VAL(val) ((int [2]){val}[0] + (int [2]){val}[1])
int main() {
printf("%d\n",ADD_VAL(GET_VAL));
}
Output
5
I have the following code:
#define TRACE_NONE 0
#define TRACE_ERROR 1
#define TRACE_WARNING 2
#define TRACE_INFORMATIONAL 3
#define TRACE_DEBUG 4
#define TINFO(str,cat,...) trace(TRACE_INFORMATIONAL,str,cat,__VA_ARGS__)
#define TWARN(str,cat,...) trace(TRACE_WARNING,str,cat,__VA_ARGS__)
#define TERROR(str,cat,...) trace(TRACE_ERROR,str,cat,__VA_ARGS__)
#define TDEBUG(str,cat,...) trace(TRACE_DEBUG,str,cat,__VA_ARGS__)
On the #define TINFO line I'm getting
error: expected primary-expression before ')' token
When I use it like this
TINFO("Session start","SES");
Edit: But if i supply a 3rd argument, like
TINFO("Session start","SES","");
everything works.
I want the first variant to work
My function signature for trace is this:
void trace(int level,const char* sz,const char* cat,...);
If it matters
I don't really use __VA_ARGS__ - the last time I used it was years ago, and I just can't seem to find what I'm doing wrong here, after looking at several examples. I'm missing something easy - I know I am - but I don't know what it is for the life of me.
This code can be GCC specific.
After some experimentation, I found I needed to use ##
#define TINFO(str,cat,...) trace(TRACE_INFORMATIONAL,str,cat, ##__VA_ARGS__ )
#define TWARN(str,cat,...) trace(TRACE_WARNING,str,cat, ##__VA_ARGS__ )
#define TERROR(str,cat,...) trace(TRACE_ERROR,str,cat, ##__VA_ARGS__ )
#define TDEBUG(str,cat,...) trace(TRACE_DEBUG,str,cat, ##__VA_ARGS__ )
That worked. I had tried VA_OPT but it wasn't working because apparently my toolchain uses an old compiler (I'm cross compiling for a microcontroller and i'm not used to the toolchain yet)
I am trying to implement VERSION macro for my program, that is to be changed under certain circumstances.
macro VERSION is defined via Makefile (git info is put there) and is a string.
Now I have a set of #define'd switches and I want VERSION to reflect which of them are on. This looks now like the follows (main.h):
#define COMPLEX_DEPOSITION // This is switch. later in code it is used in #ifdef...#endif construction.
#ifdef COMPLEX_DEPOSITION
#define CD "_COMP_DEP" // this is the string I want to put in the end of VERSION
#define VERSION_ VERSION CD
#undef VERSION // this is to suppress 'macro redefinition' warning
#define VERSION VERSION_
#undef VERSION_
#endif
Well, I get a lot of errors, most of which make me think that C preprocessor works with lines in file in random order:(
Later I have an even more complex thing that is intended to make VERSION -> VERSION_WLT_GAP_2
#define WIRESLIFETIMES
#ifdef WIRESLIFETIMES
#define GAP 2
#define VERSION_ (VERSION ## "_WLT_GAP_" ## #GAP)
#define VERSION VERSION_
#undef VERSION_
#endif
and I got no idea what to do and if this is even possible
String literals concatenate naturally when placed next to each other
"foo" "bar" is the same as "foobar".
As for the second example, you probably want:
#define CAT_(A,B) A##B
#define CAT(A,B) CAT_(A,B)
#define GAP 2
#define VERSION CAT(VERSION_WLT_GAP_ , GAP)
VERSION //expands to VERSION_WLT_GAP_2
I recommend playing with gcc -E/clang -E a bit, to learn how macros work,
before trying to compose anything complex with them.
Well, the answer seems to be the following:
// https://stackoverflow.com/questions/5256313/c-c-macro-string-concatenation
// Concatenate preprocessor tokens A and B without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded).
#define PPCAT_NX(A, B) A ## B
// Concatenate preprocessor tokens A and B after macro-expanding them.
#define PPCAT(A, B) PPCAT_NX(A, B)
// Turn A into a string literal without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded).
#define STRINGIZE_NX(A) #A
// Turn A into a string literal after macro-expanding it.
#define STR(A) STRINGIZE_NX(A)
#define COMPLEX_DEPOSITION
#ifdef COMPLEX_DEPOSITION
#define CD "_COMPDEP"
#else
#define CD ""
#endif
#define WIRESLIFETIMES
#ifdef WIRESLIFETIMES
#define GAP 2
#define WLT STR(PPCAT(_WLT:G, GAP))
#define DISABLE_METROPOLIS
#else
#define WLT ""
#endif
#define VERSION VERSIONX CD WLT
which produces V008.1-11-g68a9c89cb4-dirty_COMPDEP_WLT:G2 and I am happy with it.
Must be noted that I changed -DVERSION=... to -DVERSIONX=... inside Makefile
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 macro paste
concatenates its two arguments:
#define paste(front, back) front ## back
so paste(name, 1) creates the token
name1.
How and why would someone use this in the real world? What are practical examples of its use, and are there gotchas to consider?
One thing to be aware of when you're using the token-paste ('##') or stringizing ('#') preprocessing operators is that you have to use an extra level of indirection for them to work properly in all cases.
If you don't do this and the items passed to the token-pasting operator are macros themselves, you'll get results that are probably not what you want:
#include <stdio.h>
#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)
#define BAD_PASTE(x,y) x##y
#define BAD_STRINGIFY(x) #x
#define SOME_MACRO function_name
int main()
{
printf( "buggy results:\n");
printf( "%s\n", STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
printf( "%s\n", BAD_STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
printf( "%s\n", BAD_STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
printf( "\n" "desired result:\n");
printf( "%s\n", STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
}
The output:
buggy results:
SOME_MACRO__LINE__
BAD_PASTE( SOME_MACRO, __LINE__)
PASTE( SOME_MACRO, __LINE__)
desired result:
function_name21
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;
Here's a gotcha that I ran into when upgrading to a new version of a compiler:
Unnecessary use of the token-pasting operator (##) is non-portable and may generate undesired whitespace, warnings, or errors.
When the result of the token-pasting operator is not a valid preprocessor token, the token-pasting operator is unnecessary and possibly harmful.
For example, one might try to build string literals at compile time using the token-pasting operator:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a##+##b)
#define NS(a, b) STRINGIFY(a##::##b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
On some compilers, this will output the expected result:
1+2 std::vector
On other compilers, this will include undesired whitespace:
1 + 2 std :: vector
Fairly modern versions of GCC (>=3.3 or so) will fail to compile this code:
foo.cpp:16:1: pasting "1" and "+" does not give a valid preprocessing token
foo.cpp:16:1: pasting "+" and "2" does not give a valid preprocessing token
foo.cpp:16:1: pasting "std" and "::" does not give a valid preprocessing token
foo.cpp:16:1: pasting "::" and "vector" does not give a valid preprocessing token
The solution is to omit the token-pasting operator when concatenating preprocessor tokens to C/C++ operators:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a+b)
#define NS(a, b) STRINGIFY(a::b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
The GCC CPP documentation chapter on concatenation has more useful information on the token-pasting operator.
This is useful in all kinds of situations in order not to repeat yourself needlessly. The following is an example from the Emacs source code. We would like to load a number of functions from a library. The function "foo" should be assigned to fn_foo, and so on. We define the following macro:
#define LOAD_IMGLIB_FN(lib,func) { \
fn_##func = (void *) GetProcAddress (lib, #func); \
if (!fn_##func) return 0; \
}
We can then use it:
LOAD_IMGLIB_FN (library, XpmFreeAttributes);
LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer);
LOAD_IMGLIB_FN (library, XpmReadFileToImage);
LOAD_IMGLIB_FN (library, XImageFree);
The benefit is not having to write both fn_XpmFreeAttributes and "XpmFreeAttributes" (and risk misspelling one of them).
A previous question on Stack Overflow asked for a smooth method of generating string representations for enumeration constants without a lot of error-prone retyping.
Link
My answer to that question showed how applying little preprocessor magic lets you define your enumeration like this (for example) ...;
ENUM_BEGIN( Color )
ENUM(RED),
ENUM(GREEN),
ENUM(BLUE)
ENUM_END( Color )
... With the benefit that the macro expansion not only defines the enumeration (in a .h file), it also defines a matching array of strings (in a .c file);
const char *ColorStringTable[] =
{
"RED",
"GREEN",
"BLUE"
};
The name of the string table comes from pasting the macro parameter (i.e. Color) to StringTable using the ## operator. Applications (tricks?) like this are where the # and ## operators are invaluable.
You can use token pasting when you need to concatenate macro parameters with something else.
It can be used for templates:
#define LINKED_LIST(A) struct list##_##A {\
A value; \
struct list##_##A *next; \
};
In this case LINKED_LIST(int) would give you
struct list_int {
int value;
struct list_int *next;
};
Similarly you can write a function template for list traversal.
The main use is when you have a naming convention and you want your macro to take advantage of that naming convention. Perhaps you have several families of methods: image_create(), image_activate(), and image_release() also file_create(), file_activate(), file_release(), and mobile_create(), mobile_activate() and mobile_release().
You could write a macro for handling object lifecycle:
#define LIFECYCLE(name, func) (struct name x = name##_create(); name##_activate(x); func(x); name##_release())
Of course, a sort of "minimal version of objects" is not the only sort of naming convention this applies to -- nearly the vast majority of naming conventions make use of a common sub-string to form the names. It could me function names (as above), or field names, variable names, or most anything else.
I use it in C programs to help correctly enforce the prototypes for a set of methods that must conform to some sort of calling convention. In a way, this can be used for poor man's object orientation in straight C:
SCREEN_HANDLER( activeCall )
expands to something like this:
STATUS activeCall_constructor( HANDLE *pInst )
STATUS activeCall_eventHandler( HANDLE *pInst, TOKEN *pEvent );
STATUS activeCall_destructor( HANDLE *pInst );
This enforces correct parameterization for all "derived" objects when you do:
SCREEN_HANDLER( activeCall )
SCREEN_HANDLER( ringingCall )
SCREEN_HANDLER( heldCall )
the above in your header files, etc. It is also useful for maintenance if you even happen to want to change the definitions and/or add methods to the "objects".
SGlib uses ## to basically fudge templates in C. Because there's no function overloading, ## is used to glue the type name into the names of the generated functions. If I had a list type called list_t, then I would get functions named like sglib_list_t_concat, and so on.
I use it for a home rolled assert on a non-standard C compiler for embedded:
#define ASSERT(exp) if(!(exp)){ \
print_to_rs232("Assert failed: " ## #exp );\
while(1){} //Let the watchdog kill us
I use it for adding custom prefixes to variables defined by macros. So something like:
UNITTEST(test_name)
expands to:
void __testframework_test_name ()
One important use in WinCE:
#define BITFMASK(bit_position) (((1U << (bit_position ## _WIDTH)) - 1) << (bit_position ## _LEFTSHIFT))
While defining register bit description we do following:
#define ADDR_LEFTSHIFT 0
#define ADDR_WIDTH 7
And while using BITFMASK, simply use:
BITFMASK(ADDR)
It is very useful for logging. You can do:
#define LOG(msg) log_msg(__function__, ## msg)
Or, if your compiler doesn't support function and func:
#define LOG(msg) log_msg(__file__, __line__, ## msg)
The above "functions" logs message and shows exactly which function logged a message.
My C++ syntax might be not quite correct.