C:结合体内结构域的位置

时间:2013-01-22 03:22:10

标签: c struct unions specifications

我有以下类型:

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],依此类推?

如果没有,它有多大可能起作用?如果我依赖它,是否存在破坏我的代码的编译器/平台?

3 个答案:

答案 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.namedstate.named.c0state.array。但是,这里有捕获,无法保证其余named成员所在的位置(指定 order 在内存中,但 location 不是)。从技术上讲,可以在每个named成员之间填充(甚至在named的末尾)。所以答案是不,这是无法保证的。可以在您的成员之间添加填充。

关键是第一句话的最后一句:

  

结构对象中可能存在未命名的填充

答案 2 :(得分:-3)

state.array[0]state.named.c0相同。 C保证'array [16]`和命名的结构将占用相同的内存区域。

只要数据类型匹配,就是这样。例如,如果您要存储2个排序然后读取整数,则结果取决于机器。