我一直在研究在C11前C中实现结构“多态”的非传统方式。假设我们有2个结构:
struct s1 {
int var1;
char var2;
long var3;
};
struct s2 {
int var1;
char var2;
long var3;
char var4;
int var5;
};
在大多数编译器中,我们可以安全地在指向两者的指针之间进行转换,然后在没有填充的情况下访问公共的第一个成员。但是,这不是标准化的行为。
现在,我在C标准中找到了以下一行,直到C89:
为了简化联合的使用,我们做了一个特别的保证:如果一个联合包含几个共享一个公共初始序列的结构,并且如果联合对象当前包含这些结构中的一个,则允许检查公共初始他们中的任何一个。如果相应的成员具有一个或多个初始成员的序列的兼容类型,则两个结构共享共同的初始序列。
它还说明了以下内容:
指向联合对象的指针(适当地强制转换)指向其每个成员(或者如果成员是位字段,则指向它所在的单位),反之亦然。
现在,如果我创建这两个结构的联合:
union s2_polymorphic {
struct s1 base;
struct s2 derived;
};
并以这种方式使用它:
union s2_polymorphic test_s2_polymorphic, *ptest_s2_polymorphic;
struct s2 *ptest_s2;
struct s1 *ptest_s1;
ptest_s2_polymorphic = &test_s2_polymorphic;
ptest_s2 = (struct s2*)ptest_s2_polymorphic;
ptest_s2->var1 = 1;
ptest_s2->var2 = '2';
ptest_s1 = (struct s1*)ptest_s2;
printf("ptest_s1->var1 = %d\n", ptest_s1->var1);
printf("ptest_s1->var2 = %c\n", ptest_s1->var2);
编译并运行良好并在 gcc(GCC)4.8.3 20140911 上给出输出
ptest_s1->var1 = 1
ptest_s1->var2 = 2
根据上面给出的标准中的引用,行为是否会明确定义?
答案 0 :(得分:2)
经过一番研究,我认为我对这个问题有一个合格的答案。
给出的引用来自C89标准。 C99和C11改编得像这样:
为了简化联合的使用,我们做了一个特别的保证:如果一个联合包含几个共享一个共同初始序列的结构(见下文),并且如果联合对象当前包含这些结构中的一个,则允许检查其中任何一个的共同初始部分可以看到完整类型的联合声明。
最后一部分可以用各种方式解释,恕我直言。但是,委员会将其保留原样。据他们说,这意味着检查"共同的初始部分"结构只能 使用已声明包含它们的union
类型的对象完成。这在this question中得到了很好的证明。
C89怎么样,似乎允许我尝试做什么?那么,在符合C89的编译器中,是的,这应该有效。但是,它可能并不真正需要:我不知道一个严格的符合C89的编译器,它支持严格的别名,因此,使用它们,更容易简单地将具有公共初始序列的结构转换为每个其他类型,并尽量不给他们不同的包装设置。结果应该是一样的。