如何在结构体中实现带编译期校验的泛型函数指针?
实现带编译期类型校验的结构体泛型push_str方法
现有代码
我的头文件String.h代码如下:
typedef struct String String; typedef String* String_t; ... struct String { //... other methods void (*push_str)(String_t self, void *str); ??? }; void string_push_cstr(String_t self, char * str); void string_push_slice(String_t self, Slice_t str); void string_push_string(String_t self, String_t str); #define string_push_str(self, str) _Generic(str, \ char*: string_push_cstr, \ String_t: string_push_string, \ Slice_t: string_push_slice \ )(self, str);
问题
能否在String结构体中添加泛型push_str函数指针,使其拥有和上述宏string_push_str完全一致的API与编译期类型校验能力?要求不允许使用Union类型或额外参数。
我自己试了一个不够优雅的技巧,通过宏包装调用逻辑,但会多一次无意义的空函数调用:
#define push_str(self, str) dummy();_Generic(str, \ char*: string_push_cstr, \ String_t: string_push_string, \ Slice_t: string_push_slice \ )(self, str);
其中dummy是String结构体中定义的空操作(nop)函数指针,预处理后执行逻辑不变,但会额外触发一次空函数调用。
可行方案
C语言的函数指针本身不支持泛型签名,结构体成员的函数指针只能是固定参数类型,但我们可以通过宏+_Generic的组合,在保留类成员调用语法的同时,实现编译期类型校验,且避免冗余的空函数调用。
具体实现
- 保留结构体中的push_str占位
结构体里的push_str函数指针仅作为语法占位,可以指向任意一个同签名的合法函数(避免编译警告),实际不会通过它直接调用:
struct String { //... other methods void (*push_str)(String_t self, void* str); }; // 初始化结构体时给push_str赋值一个默认实现(比如string_push_cstr) String_t string_new() { String_t s = malloc(sizeof(String)); // 强制类型转换适配签名 s->push_str = (void(*)(String_t, void*))string_push_cstr; //... 其他成员初始化 return s; }
- 用宏实现泛型分发与校验
直接基于_Generic定义宏,模拟结构体成员调用的语法,同时完成编译期类型校验和函数分发:
#define push_str(self, str) _Generic((str), \ char*: string_push_cstr, \ String_t: string_push_string, \ Slice_t: string_push_slice \ )(self, str)
- 使用方式
调用时直接使用宏,语法和结构体成员调用几乎一致,且编译期会自动校验str的类型:
String_t my_str = string_new(); push_str(my_str, "hello world"); // 自动分发到string_push_cstr,编译期校验char*类型 push_str(my_str, another_string); // 自动分发到string_push_string,编译期校验String_t类型 push_str(my_str, some_slice); // 自动分发到string_push_slice,编译期校验Slice_t类型
为什么这个方案可行?
_Generic是C11标准引入的编译期类型选择机制,能在编译阶段根据str的类型匹配到对应的处理函数,完全满足编译期校验需求。- 不需要额外的空函数调用,宏展开后直接调用目标函数,性能无损耗。
- 语法简洁,和原有的
string_push_str宏用法一致,也贴近结构体成员函数的调用习惯。
内容的提问来源于stack exchange,提问作者u23r
相关产品推荐
相关产品推荐

