ISO / IEC C9899:1999标准的6.7.8.10章描述了如何初始化具有静态存储持续时间的并集:
如果具有自动存储持续时间的对象未初始化 显然,它的值是不确定的。如果对象具有静态 存储期限未明确初始化,则:
- 如果具有指针类型,则将其初始化为空指针;
- 如果具有算术类型,则将其初始化为(正数或无符号)零;
- 如果是聚合,则根据这些规则(递归)初始化每个成员;
- 如果是联合,则将根据这些规则(递归)初始化第一个命名成员。
让我们假设我们有以下代码,实际上,联合的第二个成员比联合的第一个成员具有更大的内存占用量:
typedef struct
{
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} my_structure_t;
typedef union
{
uint8_t *first_member;
my_structure_t later_member;
} my_union_t;
static my_union_t data;
是否在C标准的某个地方定义了later_member
所占用的存储区将如何初始化?因为下面的语句我怀疑这是实现定义的行为,但是我需要确认,至少需要链接到某些gcc,clang,ghs文档(在其中进行了描述)。
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1311.pdf
然后是DR_016(问题2)的开头:这是 仅与空指针或浮点型的硬件相关 点零/不/表示为全零位。 它处理
union { char *p; int i; } x;
然后指出:
如果空指针是 表示为0x80000000,则没有办法隐式 初始化此对象。 p成员包含null 指针,或者i成员包含0,但不能同时包含两者。所以行为 该翻译单位的不确定。这是一个糟糕的状态 事务。我认为委员会的意图不是禁止 一大类隐式初始化的联合;这将使 现有代码大量不一致。
问题主要针对C99标准,但是非常欢迎与其他C标准进行比较。
答案 0 :(得分:2)
因为仅初始化union
的第一个命名成员,所以属于其他成员的所有其他剩余字节保持未初始化状态,并且具有不确定值,并且任何尾随填充都设置为0。
您在C11中使用与上述相同的子句:
如果是联合,则根据以下内容(递归)初始化第一个命名成员 规则,,并且任何填充都初始化为零位;
由于union
一次只能包含一个成员,因此不设置与其他成员相对应的字节不是问题,因为标准规定您无论如何都不应该读取它们。
答案 1 :(得分:1)
根据C99标准(具有静态存储期限且未显式初始化的联合对象),编译器应(递归)初始化第一个命名成员 1)。因此,如果第一个成员的大小大于union的第一个命名成员,则不应对成员的值做任何假设,因为按照标准,编译器将仅初始化union的第一个命名成员并保留剩余字节大于第一个命名成员的成员中的成员未初始化。
C标准未提及有关数据段(已初始化/未初始化),堆栈,堆等的任何内容。这些都是特定于体系结构/平台的。对于对象初始化(在静态存储持续时间的情况下),C标准仅指定要初始化为0
/ NULL
的内容,而不指定要初始化的内容,并且不指定哪个存储持续时间对象进入哪个段。标准规范是针对编译器的,希望遵循良好的编译器。通常,0
初始化的静态数据进入.BSS
(以符号开头的块),非0
初始化的数据进入.DATA
(数据段)。因此,您可能会发现later_member
结构(这是并集my_union_t
的第二个成员)成员值0
,但这并非总是如此。
C11标准包括有关联合的填充字节的规范(按照6.7.9p10)[已加重]:
10如果未自动初始化具有自动存储期限的对象,则其值不确定。如果未明确初始化具有静态或线程存储持续时间的对象,则: ......
......
- 如果是联合,则将根据这些规则初始化(递归)第一个命名成员,并且将任何 padding初始化为零位;
答案 2 :(得分:-1)
理论上,仅将指针清零,但通常将整个.bss部分清零。为了确保只是更改成员的顺序。