在C中优化标记的联合

时间:2018-04-07 20:15:21

标签: c unions

我在个人项目中使用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;
};

是否有更有效的方式来实施print_data,没有人工检查dtype的每个案例?如果C允许类型列表,我将使用enum迭代它,但这不是一个可用的实用程序。我需要一种通用的方法来实现这一点,因为我计划在联合中添加大量数据类型。

这可能吗?如果没有,在这种情况下,对我来说,更好的策略是什么?

1 个答案:

答案 0 :(得分:2)

您可以利用这样一个事实,即指向struct-object的指针可以被视为指向其第一个成员的指针。因此,在交换dtypedata时,您可以通过某种通用方式访问所有成员:

struct data_unit {
    union {
        char a;
        int b;
        double c;
    } data;
    enum {
        d_A, d_B, d_C
    } dtype;
};

typedef void (print_data_unit) (struct data_unit *du);

void print_data_unit_char(struct data_unit *du) {
    printf("%c\n", *((char*)(du)));
}
void print_data_unit_double(struct data_unit *du) {
    printf("%lf\n", *((double*)(du)));
}
void print_data_unit_int(struct data_unit *du) {
    printf("%d\n", *((int*)(du)));
}

static print_data_unit* functions[3] = { print_data_unit_char, print_data_unit_int, print_data_unit_double };

void print_data(struct data_unit du) {
    functions[du.dtype](&du);
}

int main() {

    struct data_unit du;

    du.dtype = 0;
    du.data.a = 'c';
    print_data(du);

    du.dtype = 1;
    du.data.b = 100;
    print_data(du);

    du.dtype = 2;
    du.data.c = 200.55;
    print_data(du);
}