我试图在未明确初始化的情况下解释与 union 的静态(和线程本地)初始化有关的C11 standard
第6.7.9 10节(第139页)规定:

假设我们使用的是amd64架构,则需要执行以下语句:

static union { uint32_t x; uint16_t y[3]; } u;
u.y[2]可以包含非零值吗,还是因为被视为填充而将其初始化为零?
我已经搜索了C11标准,但是对于什么是 union 中的填充几乎没有解释。在C99 standard (pg 126)中未提及填充,因此在这种情况下u.y[2]可以为非零。

最佳答案

y所使用的,x未使用的额外空间不被视为填充。 C11 standard关于“结构和 union 说明符”的第6.7.2.1p17节规定:



您的示例中y使用的字节而不是x使用的字节仍被命名,因此不进行填充。

您的示例很可能确实具有这种未命名的填充,因为最大的成员占用6个字节,但是其中一个成员是uint32_t,通常需要4个字节对齐。实际上,在gcc 4.8.5上,此 union 的大小为8个字节。因此,该 union 的内存布局如下所示:

            -----  --|       ---|
         0  | 0 |    |          |
            -----    |          |-- y[0]
         1  | 0 |    |          |
            -----    |-- x   ---|
         2  | 0 |    |          |
            -----    |          |-- y[1]
         3  | 0 |    |          |
            -----  --|       ---|
         4  | 0 |               |
            -----               |-- y[2]
         5  | 0 |               |
            -----            ---|
         6  | 0 |  -- padding
            -----
         7  | 0 |  -- padding
            -----

因此,请严格阅读标准,以获取没有显式初始化程序的该 union 的静态实例:
  • 对应于x(即第一个命名成员)的字节0-3初始化为0,导致x为0。
  • 对应于y [2]的字节4-5保留为且未初始化,并且的不确定值
  • 对应于填充的字节6-7初始化为0。

  • 我在gcc 4.8.5,clang 3.3和MSVC 2015上对此进行了测试,并且它们都在各种优化设置下将字节均设置为0。但是,严格地阅读标准并不能保证其行为,因此,这些编译器的不同优化设置,它们的不同版本或完全不同的编译器仍有可能做不同的事情。

    从实用的角度来看,对于编译器而言,将静态对象的所有字节简单地设置为0以满足此要求是有意义的。当然,这是假设没有整数类型具有填充,浮点类型是IEEE754,而NULL指针的数值为0。在大多数人可能会遇到的大多数系统上,都是这种情况。并非如此的系统可能会将这些字节设置为非0的值。因此,再次说明,尽管这些字节可能设置为0,但不能保证。

    要记住的重要一点是,根据6.7.2.1p16,一个 union 一次只能存储一个成员:



    因此,如果未初始化具有静态存储持续时间的union,则仅安全访问第一个成员,因为该成员是隐式初始化的。

    唯一的异常(exception)是,如果 union 包含具有一组公共(public)初始成员的结构,则在这种情况下,您可以访问内部结构的任何公共(public)元素。第6.5.2.3p6节对此进行了详细说明:

    关于c - 什么是 union 中的填充?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54160137/

    10-11 23:10
    查看更多