【发布时间】:2015-03-09 11:08:43
【问题描述】:
我一直在研究在 C11 C 之前的 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
根据上面给出的标准的引用,行为是否得到明确定义?
【问题讨论】:
-
我可能误解了您在这里所做的事情,但在
union的示例中,不应该s2(即derived)现在不复制s1的内容吗? IE不应该只包含额外的元素吗? -
"行为是否明确" 我会说:是的。是什么让你怀疑这一点?
-
@abligh:我可能误解了你的问题......你所说的“只包含额外的元素”是什么意思?
-
@Mints97 其实这种方法很常见。通常第一个成员用于指定实际类型。这被称为“智能联合”
-
@Mints97 考虑一下内存使用、多重继承和信息隐藏,您也会看到这种方法的一些缺点,不是吗?