Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C “是多层次的”;“结构继承”;保证到处工作?_C_Struct - Fatal编程技术网

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)); // ..

我知道在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
是a
B
,因此该条款还规定
(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
),我看不到任何场景支持对动态分配案例标准的不同解释,而适用于其他案例。实际上,我并不期望任何实现都需要通过最具体的类型进行初始访问。

不清楚您的问题是什么。只要my
malloc()
获得的内存足够大,可以容纳
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;