我相信标题是不言自明的,但这里有一个例子来说明我想要完成的事情:
#define PASTE2(_0, _1) _0 ## _1
#define DEFINE_OPS_FOR_TYPE(TYPE) \
int PASTE2(do_something_with_, TYPE)(void) { \
/* do_something_with_<TYPE> */ \
}
一切都适用于char
,int
和单一措辞类型,但是当涉及unsigned
类型或其他具有多个关键字的类型时,使用标记粘贴(a ## b
)不会因空白而生成有效名称(例如:do_something_with_foo bar
) 。
我能想到的最简单的解决方案是更改DEFINE_OPS_FOR_TYPE
宏以将有效名称作为第二个参数。例如:
#define DEFINE_OPS_FOR_TYPE(TYPE, NAME_FOR_TYPE) \
int PASTE2(do_something_with_, NAME_FOR_TYPE)(void) { \
/* do_something_with_<NAME_FOR_TYPE> */ \
}
这可以按预期工作,但我很好奇其他可能的解决方案,即使它们过于复杂。我想过使用_Generic
,但我没看到它如何帮助定义一个名字。
你能想到另一种解决方案吗?
在你想要做的符号的声明或定义的层面上,没有太多办法将typedef
ing事物转换为相关类型的唯一标识符。 _Generic
或等效的替换太晚了,对预处理器没用。
但是只有有限数量的标准类型会造成这样的问题。所以你可以很容易地提出一个类型deffing的约定。
_Generic
可以帮助您使用此类已定义符号的使用方面。在这里你可以做类似的事情
_Generic((X),
unsigned long: do_something_with_ulong,
unsigned char: do_something with_uchar,
...
)(X)
在P99我遵循这个方案,你会发现它已经有很多支持宏。
我最终使用了一个带有空参数的宏。例:
#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)));
正如你可以see here,输出是:
int
unsignedint
unsignedlonglong
我不记得是否根据标准很好地定义了使用空宏参数,但我可以告诉你,Clang 3.1没有为-std=c11
发出-pedantic
的任何警告。
如果您想尝试以下是一些代码:
#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
}