我试图在未明确初始化的情况下解释与 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。我在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/