这是对于一个有关打印不同结构体中的共同成员问题的后续。
我认为联合体可以允许检查它们两个元素的共同初始序列。因此,我最终用了以下代码:
#include <stdio.h>
struct foo {
const char *desc;
float foo;
};
struct bar {
const char *desc;
int bar;
};
union foobar {
struct foo foo;
struct bar bar;
};
void printdesc(const union foobar * fb) {
printf("%s\n", fb->foo.desc); // allowed per 6.5.2.3 Structure and union members
}
int main() {
struct bar bb = {"desc bar", 2};
union foobar fb = { .bar=bb};
printdesc((union foobar *) &(fb.bar)); // allowed per 6.7.2.1 Structure and union specifiers
printdesc((union foobar *) &bb); // legal?
return 0;
}
它可以在没有任何警告的情况下编译,并且给出了预期的结果。
desc bar
desc bar
这里关键的是带有// legal?注释的那一行。我已经将一个
bar *
转换为了foobar *
。当bar
是foobar
联合体的成员时,根据6.7.2.1结构和联合体说明符,这是允许的。但在这里,我不确定。如果
bar
没有声明为foobar
的成员,那么将指向bar
对象的指针转换为指向foobar
对象的指针是合法的吗?问题并不是关于它是否可以在特定编译器中工作。我相当确定,在它们当前的版本中,所有常用的编译器都能够处理。问题是关于它是否是合法的C代码。
以下是我的研究结果。
来自C11草案n1570的参考文献:
6.5.2.3 结构体和联合体成员§6
6.7.2.1 结构体和联合体说明符§16... 如果一个联合包含多个共享公共初始序列(见下文)的结构体,并且如果该联合对象当前包含其中之一,则允许检查它们中任何一个的公共初始部分...
... 适当转换后,指向联合对象的指针指向其每个成员......反之亦然...
union U { Member1 m1; Member2 m2; }
。进一步地,给定union U *up;
,'suitably converted'的注释意味着Member1 *mp1 = (Member1 *)up;
是良好定义的,Member2 *mp2 = (Member2 *)up;
也是如此。尝试OtherType *otp = (OtherType *)up;
不是“适当转换”,Member1 *mp1 = (Member2 *)up;
也不是——尽管后者的结果可能相同,即使它不是“适当转换”。 - Jonathan Leffler