C “是多层次的”;“结构继承”;保证到处工作?
我知道在C中,结构的第一个成员之前保证没有填充。因此,C “是多层次的”;“结构继承”;保证到处工作?,c,struct,C,Struct,我知道在C中,结构的第一个成员之前保证没有填充。因此,&mystruct==&mystruct.firstmember总是正确的 这允许使用“结构继承”技术: 然而,我想确保它在无限层“继承”的情况下能够安全工作。例如: 是否保证以下所有用途均有效 A* a = (A*) malloc(sizeof(B)); A* a = (A*) malloc(sizeof(C)); B* b = (B*) malloc(sizeof(C)); C* c = malloc(sizeof(C)); // ..
&mystruct==&mystruct.firstmember
总是正确的
这允许使用“结构继承”技术:
然而,我想确保它在无限层“继承”的情况下能够安全工作。例如:
是否保证以下所有用途均有效
A* a = (A*) malloc(sizeof(B));
A* a = (A*) malloc(sizeof(C));
B* b = (B*) malloc(sizeof(C));
C* c = malloc(sizeof(C));
// ... use and access members through the pointers
编辑:
让我澄清一下我的问题。C标准是否保证以下“多级继承”的使用有效
C* c = malloc(sizeof(C));
// ... initialize fields in c
A* a = (A*) c;
// ... use A fields in a
B* b = (B*) a;
// ... use B fields in b
B* b = (B*) c;
// ... use B fields in b
c = (C*) a;
// ... go back to using C fields in c
ISO C标准要求在以下情况下工作:
union U {
struct X x;
struct Y y;
struct Z z;
/* ... */
};
如果结构共享一些成员的公共初始序列,则可以通过任何成员访问该初始序列。例如:
struct X {
/* common members, same as in Y and Z: */
int type;
unsigned flags;
/* different members */
};
如果所有结构具有相同顺序和相同类型的类型
和标志
,则需要执行以下操作:
union U u;
u.x.type = 42; /* store through x.type */
foo(u.y.type); /* access through y.type */
这种类型的其他黑客不受ISO C的“祝福”
你在那里的情况有点不同。问题是,给定一个结构的前导成员,我们是否可以将指向该结构的指针转换为该成员的类型,然后使用它。最简单的情况如下:
struct S {
int m;
};
给定一个对象struct S
,我们可以使用&S.m
获取m
的地址,获得一个int*
指针。同样地,我们可以使用(int*)和s
获得相同的指针
ISO C确实要求结构与其第一个成员具有相同的地址;指向结构的指针和指向第一个成员的指针具有不同的类型,但指向相同的地址,我们可以在它们之间进行转换
这不受嵌套级别的限制。给定此类型的a
:
struct A {
struct B {
struct C {
int m;
} c;
} b
};
地址&a.b.c.m
仍然与地址&a
相同。指针&a.b.c.m
与(int*)和
相同,您描述的那种“多级继承”必须遵循相同的原则——在您引用的另一个Q&a中进行了解释——这使得这种继承能够工作。具体而言,本标准明确规定,在适用类型之间转换结构及其初始构件的地址具有预期效果:
指向结构对象的指针
转换后,指向其初始成员[…],反之亦然
(第6.7.2.1/15段)
请考虑此声明,相对于所提供的结构定义:
C c;
引用的条款规定&c==(c*)&c.base
和(B*)&c==&c.base
均为真
但是c.base
是aB
,因此该条款还规定(a*)&c.base==&c.base.base
和&c.base==(B*)&c.base.base
均为真
由于(B*)&c==&c.base
是真的,&c.base==(B*)&c.base.base
都是真的,因此(B*)&c==(B*)&c.base.base
也是真的
将两边都转换为A*
或C*
也会产生等式(A*)&C==&C.base.base
和&C==(C*)&C.base.base
这种推理可以扩展到任意嵌套深度
对于动态分配的结构与严格的别名规则,人们可能会有一些疑惑,但没有理由认为在这种情况下,它的工作方式会有任何不同,只要首先通过最特定类型的左值访问动态分配的空间(
C
),我看不到任何场景支持对动态分配案例标准的不同解释,而适用于其他案例。实际上,我并不期望任何实现都需要通过最具体的类型进行初始访问。不清楚您的问题是什么。只要mymalloc()
获得的内存足够大,可以容纳T
类型的对象,通过T
类型的左值表达式对其进行(写-)访问都是定义良好的,不管计算malloc()参数的确切表达式是什么
was.@EOF请看我的编辑。OP描述的类型的黑客肯定受到标准C的祝福。union
方法也可以,但这不是OP所问的。谢谢你的详细回答。实际上,这里有一点令人担忧:严格的别名规则。你提到这件事后,我就去读了。据我所知(如果我错了,请纠正我),规则基本上说,如果类型X与类型Y不兼容,就永远不能将类型X的指针解引用到类型Y的对象。这不正是我们在做的事情时违反的吗,例如a*a=(a*)c代码>?在这个答案()中,它说标准还允许指针指向不同类型的对象,如果指针指向“…在其成员中包括上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的成员)”。这是使“继承”技术合法化的例外吗?如果是这样的话,为什么你会提到第一次访问是通过最具体的类型进行的?从理论上讲,这有什么关系?我可能错过了什么。感谢you@AvivCohn首先,不,这里没有工会。严格别名规则的特殊例外在这里不适用,这里也不需要。您必须首先了解严格的别名规则(即本规范第6.5/7段)并不排除通过指向组件类型的指针修改复合对象的组件。不能将其解释为这样做,因为这将与数组的语义冲突,数组定义为
struct A {
struct B {
struct C {
int m;
} c;
} b
};
C c;