假设我有一些定义如下的结构:
struct foo { int a; };
struct bar { struct foo r; int b; };
struct baz { struct bar z; int c; };
C标准是否保证以下代码严格符合?
struct baz x;
struct foo *p = (void *)&x;
assert(p == &x.z.r);
这个构造的动机是提供一致的编程习惯用于转换为已知兼容的指针类型。
现在,这就是C关于结构和初始成员如何可转换的说法:
在结构对象中,非位字段成员和位字段所在的单元的地址按其声明的顺序增加。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位域,则指向它所在的单位),反之亦然。结构对象中可能有未命名的填充,但不在其开头。
这是关于void
指针转换的说法:
void
可以将指针转换为或指向任何对象类型的指针。指向任何对象类型的指针可能会被转换为指向void
并返回的指针; 结果应与原始指针相等。 C.11§6.3.2.3¶1
这就是它在转换对象指针类型时所说的:
指向对象类型的指针可能会转换为指向不同对象类型的指针。如果所得到的指针未被正确对齐(68),则该行为是未定义的。否则,当再次转换时,结果应与原始指针相等。 68)通常,“正确对齐”的概念是可传递的:如果指向类型A的指针正确对齐指向类型B的指针,而指向类型C的指针又正确对齐,则指向类型的指针A正确对齐指向类型C的指针 。C.11§6.3.2.3¶7
我从上面的理解是,通过转换将对象指针void *
转换为不同类型的对象指针是非常好的。
发布于 2018-05-22 19:55:41
(一个指向结构对象,适当地转换,点到它的初始构件)保证了以下等式:
(sruct bar *) &x == &(x.z)
(struct foo *) &(x.z) == &(x.z.r)
正如你在开始时那样struct
,不会出现填充,我对标准的理解是a struct
和它的第一个元素的地址是相同的。
所以struct foo *p = (void *) &x;
是正确的struct foo *p = (struct foo *) &x;
发布于 2018-05-22 21:10:19
为了完成分析,有必要查看如何定义指针相等的定义:
...如果一个操作数是一个指向对象类型的指针,另一个是指向合格或不合格版本的指针
void
,则前者将转换为后者的类型。 当且仅当两个指针都是空指针时,两个指针比较相等,两者都是指向同一对象的指针(包括指向一个对象和一个子对象的指针)或函数,它们都是指向同一数组最后一个元素之后的指针对象,或者一个是指向一个数组对象的末尾的指针,另一个是指向紧跟在地址空间中的第一个数组对象之后的不同数组对象的开始的指针。
所以,这里有一个说法是明确的:
(void *)&x == (void *)&x.z
§6.7.2.1¶15,§6.5.9¶5-6§6.7.2.1¶15
(void *)&x.z == &x.z.r
,§6.5.9¶5-6
(void *)&x == &x.z.r
传递的平等
(struct foo *)(void *)&x == (void *)&x
§6.3.2.3¶1,§6.5.9¶5-6
(struct foo *)(void *)&x == &x.z.r
传递的平等
https://stackoverflow.com/questions/-100008552
复制相似问题