【发布时间】:2016-05-03 13:20:33
【问题描述】:
假设我想使用 C 预处理器来定义一个函数族,其中只有一个参数类型发生变化。我们以带参数的分配函数为例:
#include <stdint.h>
#include <stdio.h>
#define type_vector(t) \
t * t##vector(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
int main() {
int32_t * p;
p = int32_tvector(10, 12);
return 0;
}
这很好用。
现在,假设我想在函数名称中使用较短的类型名称:i8 代替 int8_t,i32 代替 int32_t,等等。 我不想在宏函数声明中添加第二个参数,而是有一个“短”类型名称的定义。 基本上,我写的第一件事是:
#define sn_int8_t i8
#define sn_int32_t i32
#define sn_int64_t i64
#define sn(t) sn_##t
#define type_vector(t) \
t * sn(t)##vector(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
int main() {
int32_t * p;
p = i32vector(10, 12);
return 0;
}
但是,这不会编译,给出以下错误:
error: pasting ")" and "vector" does not give a valid preprocessing token
t * sn(t)##vector(int32_t nl, int32_t nh) \
据我了解,问题是由于“)”和“#”并排造成的。 所以我做了以下事情:
#define sn_int8_t(f) i8##f
#define sn_int32_t(f) i32##f
#define sn_int64_t(f) i64##f
#define sn2(t,f) sn_##t(f)
#define type_vector(t) \
t * sn2(t,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)
int main() {
int32_t * p;
p = i32vector(10, 12);
return 0;
}
这又可以正常工作了。
现在,假设我想为函数名称添加前缀,例如“远程_”。
简单地说
#define type_vector(t) \
t * remote_##sn2(t,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; /* malloc(...) */ \
return v; \
}
不起作用,因为 sn2 没有展开。所以我尝试了这个:
#include <stdint.h>
#include <stdio.h>
#define sn_int8_t(f) i8##f
#define sn_int32_t(f) i32##f
#define sn_int64_t(f) i64##f
#define sn2(t,f) sn_##t(f)
#define short_name(n,t,f) n##_##sn2(t,f)
#define remote_type_vector(t) \
t * short_name(remote,t,vector)(int32_t nl, int32_t nh) \
{ \
t * v = NULL; \
return v; \
}
remote_type_vector(int8_t)
remote_type_vector(int32_t)
remote_type_vector(int64_t)
int main() {
int32_t * p;
p = remote_i32vector(10, 12);
return 0;
}
基本上,这不起作用,因为宏 sn2 没有展开,给我这样的声明:
int32_t * remote_sn2(int32_t,vector)
有什么办法吗?
注意:我不想使用 C++ 模板。
【问题讨论】:
-
有些人声称这种魔法是邪恶的......
-
使用 灵活的数组成员 会让思考变得更简单。关于其余部分:TL;DR。提供minimal reproducible example。
-
“我不想在宏函数声明中添加第二个参数” - 为什么不呢?这并不是说您经常调用宏。第二个参数还允许您使用具有复合名称的类型(
char *、struct thing)而不使用typedef。 -
如果你不知道,你可以用
gcc -E检查预处理器的输出,我想所有的C编译器都有一个选项。 -
@EugeneSh。这种黑暗艺术自史前时期就已被禁止。至少在 18 世纪之前,死灵术、巫术和 C 宏的从业者通常会被逐出教会或被绞死、抽出和四分五裂。