以下代码使用gcc编译并运行正常。但我想知道这样的联合是否由标准定义,以及它是否以相同的方式适用于所有c编译器。我知道如果那些函数的参数不是指针并且彼此不兼容,它们将不起作用,但只要所有参数都是指针且参数的数量相同就不应该有问题,或者?
typedef struct node {
unsigned long int key;
} node_t;
typedef struct node1 {
unsigned long int key;
char *str;
} node1_t;
typedef struct node2 {
unsigned long int key;
void *data;
} node2_t;
typedef struct node3 {
unsigned long int key;
int numbers[256];
} node3_t;
int compare(node_t *a, node_t *b) {
printf("%ld ? %ld\n", c->key, d->key);
return c->key == d->key;
}
struct comp {
union {
int (*c0) (node_t *a, node_t *b);
int (*c1) (node1_t *a, node1_t *b);
int (*c2) (node1_t *a, node2_t *b);
int (*c3) (node1_t *a, node3_t *b);
int (*c4) (node2_t *a, node1_t *b);
int (*c5) (node2_t *a, node2_t *b);
int (*c6) (node2_t *a, node3_t *b);
int (*c7) (node3_t *a, node1_t *b);
int (*c8) (node3_t *a, node2_t *b);
int (*c9) (node3_t *a, node3_t *b);
} are;
};
int main(int argc, char *argv[])
{
node1_t a[] = {
{ 23477843258923UL, "Hello World" },
{ 10254892378892UL, "Hello Back" }
};
node2_t b[] = {
{ 83296783479803UL, NULL },
{ 52348237489832UL, (void *) &a[1] }
};
node3_t c[] = {
{ 91308823949203UL, { 3, 4, 5 } },
{ 17587832478823UL, {43, 43, 43, 86 } }
};
struct comp comp;
comp.are.c0 = compare;
comp.are.c1(&a[0], &a[1]);
comp.are.c2(&a[1], &b[0]);
comp.are.c3(&a[0], &c[1]);
comp.are.c8(&c[1], &b[1]);
}
答案 0 :(得分:3)
union
有效,但你正在做的事情不是。您不能使用一种类型将某些内容添加到union
中,然后将其与main
的结尾一起使用,除非这些类型是可转换的(感谢@Christoph的注释)。
答案 1 :(得分:1)
无论它是否有效,它都是丑陋的。 C有void *
是有原因的。
以下是如何使用它:
int compare(void *a, void *b) {
node_t *c = a, *d = b;
printf("%ld ? %ld\n", c->key, d->key);
return c->key == d->key;
}
答案 2 :(得分:0)
正如Jeremiah所说,通过一个不同的成员从一个联合中获取数据的技术上是未定义的行为(但它可能是你最接近标准化的未定义行为)。话虽如此,为什么不把工会搬到你真正想要的地方呢?你想要的是一种调用一个函数的方法,该函数需要2个节点,这些节点可能有不同类型的数据。因此,不是将两个不同数据节点的函数指针联合起来,而是将联合移动到不同数据实际所在的位置:创建一个函数,该函数需要2个节点来保存不同数据的并集,即将并集转换为Node
类,因此单个Node
类型可以包含各种类型的数据(AKA str
/ data
/ numbers
)(尽管您可能想要更改在这种情况下,int[256]
到int*
。
请注意,这是否有效高度依赖于您编译的平台(特别是调用约定)。