与第一个成员共享的结构联盟

Min*_*s97 10 c struct pointers unions

我一直在研究在C11前C中实现结构"多态"的非传统方式.假设我们有2个结构:

struct s1 {
    int var1;
    char var2;
    long var3;
};

struct s2 {
    int var1;
    char var2;
    long var3;
    char var4;
    int var5;
};
Run Code Online (Sandbox Code Playgroud)

在大多数编译器中,我们可以安全地在指向两者的指针之间进行转换,然后在没有填充的情况下访问公共的第一个成员.但是,这不是标准化的行为.

现在,我在C标准中找到了以下C89行:

为了简化联合的使用,我们做了一个特殊的保证:如果一个联合包含几个共享一个共同初始序列的结构,并且如果联合对象当前包含这些结构中的一个,则允许检查任何共同的初始部分.他们 如果相应的成员具有一个或多个初始成员的序列的兼容类型,则两个结构共享共同的初始序列.

它还说明了以下内容:

指向联合对象的指针(适当地强制转换)指向其每个成员(或者如果成员是位字段,则指向它所在的单元),反之亦然.

现在,如果我创建这两个结构的联合:

union s2_polymorphic {
    struct s1 base;
    struct s2 derived;
};
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它:

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);
Run Code Online (Sandbox Code Playgroud)

编译并运行良好,并在gcc(GCC)4.8.3 20140911上给出输出

ptest_s1->var1 = 1                                                            
ptest_s1->var2 = 2
Run Code Online (Sandbox Code Playgroud)

根据上面给出的标准的引用,这种行为是否会得到明确定义?

小智 2

经过一番研究,我想我对这个问题有了一个合格的答案。

给出的引用来自 C89 标准。C99 和 C11 的表述如下:

为了简化联合的使用,做出了一项特殊保证:如果联合包含多个共享公共初始序列的结构(见下文),并且如果联合对象当前包含这些结构之一,则允许检查公共初始序列它们中任何一个联合的完整类型声明可见的地方的初始部分。

恕我直言,最后一部分可以用多种方式解释。然而,委员会保留了原样。根据他们的说法,这意味着对结构的“公共初始部分”的检查只能使用union已声明为包含它们的类型的对象来完成。这一点在这个问题中得到了很好的体现。

C89 怎么样,它似乎允许我尝试做的事情?嗯,在符合 C89 的编译器中,是的,这应该可以工作。然而,它可能并不是真正需要的:我不知道有哪个严格符合 C89 的编译器支持严格别名,因此,使用它们,可以更轻松地简单地将具有公共初始序列的结构转换为彼此的类型并尽量不要给他们不同的包装设置。结果应该是一样的。