我有以下类型:
union {
struct {
uint32_t c0;
uint32_t k0[4];
uint32_t c1;
uint32_t v[2];
uint32_t i[2];
uint32_t c2;
uint32_t k1[4];
uint32_t c3;
} named;
uint32_t array[16];
} state;
因为“named”中的每个字段在初始化时都有意义,但在此之后我将主要用作字数组。 C是否保证state.array[0]
与state.named.c0
相同,state.array[1]
为state.named.k0[0]
,依此类推?
如果没有,它有多大可能起作用?如果我依赖它,是否存在破坏我的代码的编译器/平台?
答案 0 :(得分:3)
要回答你最令人担忧的问题,“......可能会发挥作用”,不要赌不可能,除非它是肯定的事情。它不是在这种情况下。
标准(第6.7.2.1节,第15页)规定结构的第一个成员的地址,或所有成员的地址,与地址相同结构或联合本身。对您而言,这仅表示array[16]
和named
的地址相同,并且都等同于state
的地址。但是,如果没有依赖于实现的打包,则无法保证 struct 将精确覆盖,因为标准的相同部分要求可以进行结构间打包。
例如,无论出于何种原因,使用打包方案的编译器总是以64位边界启动成员,可以按如下方式布置name
:
struct {
uint32_t c0;
**padding 4 bytes**
uint32_t k0[4];
uint32_t c1;
**padding 4 bytes**
uint32_t v[2];
uint32_t i[2];
uint32_t c2;
**padding 4 bytes**
uint32_t k1[4];
uint32_t c3;
**padding 4 bytes**
} name;
简而言之,您所保证的是name
整个所占用的内存以及工会其他成员占用的内存array[16]
将占用相同的内存,从每个的开始可寻址位置开始。在name
包装的内容下,记忆的内容取决于实施情况以及您提供的任何包装提示。
标准的一些相关部分:
<强> C99-§6.7.2.1,P6 强> 如6.2.5中所述,结构是由一系列成员组成的类型,其存储按有序序列分配,而union是由存储重叠的成员序列组成的类型。
<强> C99-§6.7.2.1,P15 强> 在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。在结构对象中可能有未命名的填充,但不是在它的开头。
<强> C99-§6.7.2.1,P16 强> 联合的大小足以包含其最大的成员。最多一个成员的值可以随时存储在union对象中。指向联合对象的指针(适当转换)指向其每个成员(或者如果成员是位字段,则指向它所在的单位),反之亦然。
<强> C99-§6.7.2.1,P17 强> 结构或联合的末尾可能有未命名的填充。
答案 1 :(得分:2)
来自C标准:
<强> 6.7.2.1/15 强>
在结构对象中,非位字段成员和位字段中的单元 驻留的地址按声明的顺序增加。 指向a的指针 结构对象,适当转换,指向其初始成员(或者如果该成员是 bit-fi eld,然后到它所在的单位),反之亦然。可能有未命名的 在结构对象中填充,但不在其开头。<强> 6.7.2.1/16 强>
联合的大小足以容纳其中最大的成员。 at的值 大多数成员可以随时存储在union对象中。 指向a的指针 联合对象,适当转换,指向其每个成员(或如果成员有点 - 现场,然后到它所在的单位),反之亦然。
强调我的。这基本上转化为具有相同地址的state.named
,state.named.c0
和state.array
。但是,这里有捕获,无法保证其余named
成员所在的位置(指定 order 在内存中,但 location 不是)。从技术上讲,可以在每个named
成员之间填充(甚至在named
的末尾)。所以答案是不,这是无法保证的。可以在您的成员之间添加填充。
关键是第一句话的最后一句:
结构对象中可能存在未命名的填充
答案 2 :(得分:-3)
是state.array[0]
与state.named.c0
相同。 C保证'array [16]`和命名的结构将占用相同的内存区域。
只要数据类型匹配,就是这样。例如,如果您要存储2个排序然后读取整数,则结果取决于机器。