c union从中获取类型

时间:2016-01-17 01:54:46

标签: c types unions

是否有可能获得联盟内部的变量类型?例如,我有工会:

typedef struct A {
    union {
        int p;
        double  d;
    } pointer;
    int a;
    struct A *next;
} myStruct;

我有功能:

myStruct *getMinInList(myStruct *root) {
    // do some things to get the smallest value in List,
    // simple and I don't write it here because it's not a point
    return smallest;
}

有时在union中是整数或者可能是double。是否有可能获得使用的信息?或者我必须写两个函数: 一个用于获取整数列表中的min元素,另一个用于获取list中的min min元素 - double?

2 个答案:

答案 0 :(得分:4)

union本质上不会存储任何额外信息,例如上次写入的成员。除非上下文显而易见,否则您应该在struct中指定另一个成员,该成员指定使用union的哪个成员。这可能是您示例中a的目的,但定义为显式type的名为enum的成员会使语义更明显(此类enum被调用标记的枚举)。然后,您的函数需要检查每个节点使用哪个成员进行最小化计算。

使用额外的type成员,代码如下所示:

typedef struct A {
    union {
        int p;
        double  d;
    } pointer;
    enum { POINTER_INT = 0, POINTER_DOUBLE } type;
    int a;
    struct A *next;
} myStruct;

static double get_value(const myStruct *x) {
    return x->type == POINTER_DOUBLE ? x->pointer.d : (double)x->pointer.p;
}

myStruct *getMinInList(myStruct *root) {
    myStruct *smallest = root;
    while (root) {
        if (get_value(root) < get_value(smallest)) {
            smallest = root;
        }
        root = root->next;
    }
    return smallest;
}

如果a有不同的目的,请添加具有上述语义的type成员。

注意:这种快速而肮脏的解决方案假设int类型的所有值都可以在double类型中准确表示。如果intdouble都是64位,则不会出现这种情况。在这种情况下,比较接近它们的大整数和双精度是非常麻烦的,因为从intdouble的转换会截断低位。可以通过测试(int)(double)root->pointer.p == root->pointer.p来检测这种截断。对于这种情况,这是一个更精细的解决方案,可以很容易地适应任何更长的整数类型:

static double get_value(const myStruct *x, int *adjust) {
    if (x->type == POINTER_DOUBLE) {
        *adjust = 0;
        return x->pointer.d;
    } else {
        double d = (double)s->pointer.p;
        *adjust = x->pointer.p - (int)d;
        return d;
    }
}

myStruct *getMinInList(myStruct *root) {
    myStruct *smallest = root;
    while (root) {
        int adjust1, adjust2;
        double val1 = get_value(root, &adjust1);
        double val2 = get_value(smallest, &adjust2);
        if (val1 < val2 || (val1 == val2 && adjust1 < adjust2)) {
            smallest = root;
        }
        root = root->next;
    }
    return smallest;
}

答案 1 :(得分:1)

你不想要一个工会,你想要一个tagged union

使用标记(可能是枚举)来描述union当前持有的值。

typedef struct A

  union {
    int p;
    double d;
  } pointer;

  //remember which field was last written
  enum { P_ACTIVE = 1, D_ACTIVE } tag;

} myStruct;  

这种类型在其他语言中更容易表达 例如,在C ++中,您可能想要的类型是variant