C语言标记联合(Tagged Unions)print_data函数高效实现问询
有没有更高效的方式实现标记联合的print_data函数(无需手动检查每个case)
我在个人项目中使用标记联合(Tagged Unions),示例代码如下:
struct data_unit { enum { d_A, d_B, d_C } dtype; union { char a; int b; double c; } data; }; void print_data(data_unit du) { switch (du.dtype) { case d_A: { printf("%c", du.data.a); break; } case d_B: { printf("%d", du.data.b); break; } case d_C: { printf("%lf", du.data.c); break; } default: break; } return; };请问是否存在无需手动检查每个case的更高效方式来实现print_data函数?
当然有办法!你可以用函数指针表来避免重复的switch-case逻辑,这样不仅能减少冗余代码,后续扩展新类型时也只需要在表中添加条目,不用修改print函数本身,维护起来更方便。
具体实现思路是:
- 先定义一个打印函数的类型,参数是
struct data_unit(用整个结构体做参数比单独传union成员更统一) - 创建一个函数指针数组,数组的索引对应你的
dtype枚举值,每个索引位置存放对应类型的打印函数 - 在
print_data里直接通过dtype作为索引,调用数组里的对应函数
看这个示例代码:
#include <stdio.h> struct data_unit { enum { d_A, d_B, d_C, d_TYPE_COUNT } dtype; union { char a; int b; double c; } data; }; // 定义打印函数类型 typedef void (*PrintFunc)(const struct data_unit*); // 各个类型的打印实现 void print_char(const struct data_unit* du) { printf("%c", du->data.a); } void print_int(const struct data_unit* du) { printf("%d", du->data.b); } void print_double(const struct data_unit* du) { printf("%lf", du->data.c); } // 默认的空打印(处理未知类型) void print_default(const struct data_unit* du) { (void)du; // 避免未使用参数警告 printf("[Unknown type]"); } // 函数指针表,索引对应dtype枚举 const PrintFunc print_table[] = { [d_A] = print_char, [d_B] = print_int, [d_C] = print_double, }; void print_data(const struct data_unit* du) { if (du->dtype < 0 || du->dtype >= d_TYPE_COUNT) { print_default(du); return; } // 直接通过索引调用对应函数,不用switch print_table[du->dtype](du); } // 测试用例 int main() { struct data_unit du1 = {.dtype = d_A, .data.a = 'X'}; struct data_unit du2 = {.dtype = d_B, .data.b = 123}; struct data_unit du3 = {.dtype = d_C, .data.c = 3.1415}; print_data(&du1); // 输出X printf("\n"); print_data(&du2); // 输出123 printf("\n"); print_data(&du3); // 输出3.141500 printf("\n"); return 0; }
这种方式的优势:
- 消除了重复的switch-case,代码更简洁
- 扩展性强:如果以后要加新的类型(比如d_D对应float),只需要添加对应的打印函数,然后在函数表和枚举里加条目就行,
print_data完全不用改 - 性能上和switch-case差不多,甚至在某些编译器优化下更高效,因为直接通过索引跳转,不用逐个判断case
另外还有一种思路是把函数指针直接放到结构体里,但这样每个结构体实例都会多存一个指针,内存开销更大,而函数指针表是全局的,只存一份,更适合这种固定类型集合的场景。
内容的提问来源于stack exchange,提问作者user189728
相关产品推荐
相关产品推荐

