问题
I believe the title is self-explanatory, but here's an example to illustrate what I'm trying to accomplish:
#define PASTE2(_0, _1) _0 ## _1
#define DEFINE_OPS_FOR_TYPE(TYPE) \
int PASTE2(do_something_with_, TYPE)(void) { \
/* do_something_with_<TYPE> */ \
}
Everything works fine for char
, int
, and single-worded types, but when it
comes to unsigned
types, or others that have multiple keywords, using token pasting (a ## b
) does not generate a valid name due to the whitespace (e.g.: do_something_with_foo bar
).
The easiest solution I could think of is to change the DEFINE_OPS_FOR_TYPE
macro
to take a valid name as the 2nd parameter. For example:
#define DEFINE_OPS_FOR_TYPE(TYPE, NAME_FOR_TYPE) \
int PASTE2(do_something_with_, NAME_FOR_TYPE)(void) { \
/* do_something_with_<NAME_FOR_TYPE> */ \
}
This works as expected, but I'm curious about other possible solutions, even if they're overly complex. I thought of using _Generic
, but I fail to see how it would help in defining a name.
Can you think of another solution?
回答1:
On the level of declaration or definition of the symbols that you want to do there is not much way out of typedef
ing things to a unique identifier for the type in question. _Generic
or equivalent replacements kick in too late to be useful for the preprocessor.
But there is only a finite number of standard types that pose such a problem. So you can easily come up with a convention for typedeffing these.
Where _Generic
can help is on the usage side of your such defined symbols. Here you can then do something like
_Generic((X),
unsigned long: do_something_with_ulong,
unsigned char: do_something with_uchar,
...
)(X)
In P99 I follow this scheme, and you would find a lot of support macros for it already in place.
回答2:
I ended up using a macro with an empty argument. Example:
#define STR2(x) # x
#define STR(x) STR2(x)
#define PASTE3(_1,_2,_3) _1 ## _2 ## _3
#define FOO(_1,_2,_3) PASTE3(_1, _2, _3)
printf("%s\n", STR(FOO(int,,)));
printf("%s\n", STR(FOO(unsigned, int,)));
printf("%s\n", STR(FOO(unsigned, long, long)));
As you can see here, the output is:
int
unsignedint
unsignedlonglong
I don't remember whether using empty macro arguments is well defined according to the standard, but I can tell you that Clang 3.1 doesn't emit any warnings for -std=c11
with -pedantic
.
Here's some code if you want to try:
#include <stdio.h>
#include <limits.h>
#define PASTE4(_1,_2,_3,_4) _1 ## _2 ## _3 ## _4
#define DEFINE_OPS_FOR_TYPE1(T1) DEFINE_OPS_FOR_TYPE2(T1,)
#define DEFINE_OPS_FOR_TYPE2(T1, T2) DEFINE_OPS_FOR_TYPE3(T1,T2,)
#define DEFINE_OPS_FOR_TYPE3(T1, T2, T3) \
int PASTE4(write_,T1,T2,T3)(FILE *file, void *data) { \
T1 T2 T3 foo; \
int written = fprintf(file, fmt_specifier(foo), *((T1 T2 T3 *)data));\
return written > 0 ? 0 : -1; \
}
#define fmt_specifier(x) \
_Generic((x), \
int: "%i", \
unsigned int: "%u", \
unsigned long long: "%llu", \
default: NULL \
)
DEFINE_OPS_FOR_TYPE1(int)
DEFINE_OPS_FOR_TYPE2(unsigned, int)
DEFINE_OPS_FOR_TYPE3(unsigned, long, long)
int main() {
int var_int = INT_MAX;
write_int(stdout, &var_int);
printf("\n");
unsigned int var_uint = UINT_MAX;
write_unsignedint(stdout, &var_uint);
printf("\n");
unsigned long long var_ullong = ULLONG_MAX;
write_unsignedlonglong(stdout, &var_ullong);
printf("\n");
return 0
}
来源:https://stackoverflow.com/questions/14137291/how-can-a-macro-define-a-valid-global-name-based-on-the-type-passed-to-it