C 什么构成工会中的填充?
我试图解释当未显式初始化时,关于联合的静态(和线程本地)初始化 第6.7.9 10节(第139页)规定如下: 如果没有显式初始化具有自动存储持续时间的对象,则其值是不确定的。如果没有显式初始化具有静态或线程存储持续时间的对象,则: -如果有指针类型,则初始化为空指针 -如果它有算术类型,则初始化为(正或无符号)零 -如果它是一个聚合,则根据这些规则(递归地)初始化每个成员,并将任何填充初始化为零位 -如果它是一个并集,则根据这些规则(递归地)初始化第一个命名成员,并将任何填充初始化为零位 假设我们使用的是amd64体系结构,给出以下声明:C 什么构成工会中的填充?,c,language-lawyer,c11,C,Language Lawyer,C11,我试图解释当未显式初始化时,关于联合的静态(和线程本地)初始化 第6.7.9 10节(第139页)规定如下: 如果没有显式初始化具有自动存储持续时间的对象,则其值是不确定的。如果没有显式初始化具有静态或线程存储持续时间的对象,则: -如果有指针类型,则初始化为空指针 -如果它有算术类型,则初始化为(正或无符号)零 -如果它是一个聚合,则根据这些规则(递归地)初始化每个成员,并将任何填充初始化为零位 -如果它是一个并集,则根据这些规则(递归地)初始化第一个命名成员,并将任何填充初始化为零位 假设我
static union { uint32_t x; uint16_t y[3]; } u;
可以u.y[2]
包含非零值,或者因为它被视为填充而将其初始化为零?
我已经浏览了C11标准,但是对于什么构成工会中的填充,几乎没有任何解释。在填充中没有提到,因此在这种情况下,
u.y[2]
可以是非零。如果存储是自动的,它可能包含任何值,因为它没有初始化。
如果存储器是静态的,它将初始化为零
填充不会影响联合,因为它是不属于结构或联合的任何成员的东西
例如,如果在您的实现中,数据被填充到8字节边界,则根本不会添加填充。此并集与下一个对象之间将有2个字节的间隔。未被
x
使用的y
所使用的额外空间不被视为填充。第6.7.2.1p17节“结构和联合规范”规定:
在结构或联合的末尾可能有未命名的填充
在您的示例中,y
使用的、未被x
使用的字节仍被命名,因此不是填充
您的示例很可能有这种未命名的填充,因为最大的成员占用6个字节,但其中一个成员是uint32\t
,通常需要4字节对齐。事实上,在GCC4.8.5上,这个联合的大小是8字节。因此,此联合体的内存布局如下所示:
----- --| ---|
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
-----
因此,严格阅读标准,对于这个联合体的静态实例,没有显式的初始值设定项:
- 对应于
(即第一个命名成员)的字节0-3被初始化为0,导致x
为0x
- 与y[2]相对应的字节4-5保持未初始化,并且具有不确定值
- 与填充相对应的字节6-7被初始化为0
联合
,则只能安全地访问第一个成员,因为它是隐式初始化的成员
唯一的例外是,如果联合体包含具有一组公共初始成员的结构,在这种情况下,您可以访问内部结构的任何公共元素。第6.5.2.3p6节对此进行了详细说明:
为了简化工会的使用,有一个特别的保证:如果工会包含
几个结构共享一个共同的初始序列(见下文),如果联合
对象当前包含其中一个结构,允许它检查公共
它们中任何一个的起始部分,即完整的联合类型声明
是可见的。两个结构共享一个
公共初始序列
如果对应的成员
具有一个或多个序列的兼容类型(对于位字段,具有相同的宽度)
最初的成员
u.y[2]是否可以包含非零值,或者是否因为被视为填充而将其初始化为零?
u.y[2]
不被视为填充。它是数组y
的一个元素,是unionu
的成员
联合体的大小仅与容纳其最大成员所需的大小相同(也可以添加额外的未命名的尾随填充物,以便于保存)
来自C标准#6.7.2.1p17
17在结构或接头的末端可能有未命名的填充物
最大的内存
#include <inttypes.h>
int main() {
static union { uint32_t x; uint16_t y[3]; } u;
}
# clang -Wpadded p.c
p.c:4:16: warning: padding size of 'union (anonymous at p.c:4:16)' with 2 bytes to alignment boundary [-Wpadded]
static union { uint32_t x; uint16_t y[3]; } u;
^
1 warning generated.