You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:52:31