共享相同第一成员的结构联合
union of structs sharing same first members
我一直在研究一种在 C11 之前的 C 中实现结构 "polymorphism" 的非传统方法。假设我们有 2 个结构:
struct s1 {
int var1;
char var2;
long var3;
};
struct s2 {
int var1;
char var2;
long var3;
char var4;
int var5;
};
在大多数编译器上,我们可以安全地在指向两者的指针之间进行转换,然后在没有填充发生的情况下访问公共的第一个成员。但是,这不是标准化行为。
现在,我在 C89 的 C 标准中找到了以下行:
One special guarantee is made in order to simplify the use of unions: If a union contains several structures that share a common initial sequence, and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them. Two structures share a common initial sequence if corresponding members have compatible types for a sequence of one or more initial members.
它还说明了以下内容:
A pointer to a union object, suitably cast, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa.
现在,如果我创建这两个结构的联合:
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
根据上面给出的标准的引用,行为是否定义明确?
经过一番研究,我认为我对这个问题有一个合格的答案。
给出的引用来自 C89 标准。 C99 和 C11 改写如下:
One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible.
恕我直言,最后一部分可以用多种方式解释。然而,委员会保留了原样。根据他们的说法,这意味着 "common initial part" 结构的检查可以 仅 使用已声明包含的 union
类型的对象来完成他们。 this question.
很好地证明了这一点
C89 怎么样,它似乎允许我尝试做的事情?好吧,在符合 C89 标准的编译器中,是的,这应该可以工作。然而,它可能并不真正需要:我不知道有一个严格符合 C89 标准的编译器支持严格别名,因此,有了它们,将具有公共初始序列的结构简单地转换为彼此的类型会更容易并尽量不要给他们不同的包装设置。结果应该是一样的。
我一直在研究一种在 C11 之前的 C 中实现结构 "polymorphism" 的非传统方法。假设我们有 2 个结构:
struct s1 {
int var1;
char var2;
long var3;
};
struct s2 {
int var1;
char var2;
long var3;
char var4;
int var5;
};
在大多数编译器上,我们可以安全地在指向两者的指针之间进行转换,然后在没有填充发生的情况下访问公共的第一个成员。但是,这不是标准化行为。
现在,我在 C89 的 C 标准中找到了以下行:
One special guarantee is made in order to simplify the use of unions: If a union contains several structures that share a common initial sequence, and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them. Two structures share a common initial sequence if corresponding members have compatible types for a sequence of one or more initial members.
它还说明了以下内容:
A pointer to a union object, suitably cast, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa.
现在,如果我创建这两个结构的联合:
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
根据上面给出的标准的引用,行为是否定义明确?
经过一番研究,我认为我对这个问题有一个合格的答案。
给出的引用来自 C89 标准。 C99 和 C11 改写如下:
One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible.
恕我直言,最后一部分可以用多种方式解释。然而,委员会保留了原样。根据他们的说法,这意味着 "common initial part" 结构的检查可以 仅 使用已声明包含的 union
类型的对象来完成他们。 this question.
C89 怎么样,它似乎允许我尝试做的事情?好吧,在符合 C89 标准的编译器中,是的,这应该可以工作。然而,它可能并不真正需要:我不知道有一个严格符合 C89 标准的编译器支持严格别名,因此,有了它们,将具有公共初始序列的结构简单地转换为彼此的类型会更容易并尽量不要给他们不同的包装设置。结果应该是一样的。