C 11联合会的空列表初始化 - 是否保证可以初始化工会的全长

C++11 empty list Initialization of a union - is it guaranteed to initialize the full length of the union?

本文关键字:初始化 是否 联合会 列表      更新时间:2023-10-16

在C 11中,我有以下联合:

union SomeData
{
    std::uint8_t Byte;
    std::uint16_t Word;
    std::uint32_t DWord;
    unsigned char String[128];
};

如果我这样初始化了联盟;

SomeData data {};

是否可以保证联盟的整个内容将"零"输出?换一种方式;联合的空列表限制器在功能上等效将联合置于零?:

memset(&data, 0, sizeof(data));

特别是我担心字符串数据。我想确保字符串的整个长度包含零。它似乎在我当前的编译器中起作用,但是规格的语言保证这始终是真实的?

如果不是:有没有更好的方法将联合的全长初始化为零?

no,不能保证将整个联盟归零。只有第一个被宣布的联盟成员加上任何填充,保证将被归零(以下证明)。

因此,为了确保联合对象的整个内存区域为零,您有以下选项:

  • 订购成员,使最大的成员首先是零。
  • 使用std::memset或等效功能。为了防止意外忘记这一点,您当然可以给SomeData一个默认的构造函数,该构造器称为此。

引用C 11:

8.5.4 [dcl.init.list]/3

T类型的对象或引用的列表命令定义如下:

  • 如果初始化器列表没有元素,并且T是具有默认构造函数的类类型,则该对象为 价值定性。

8.5 [dcl.init]/7

to value-initialize 类型T的对象表示:

  • 如果T是具有用户提供的构造函数(12.1)(12.1)的(可能是CV符合条件的)类类型(第9条),则 T的默认构造函数称为(如果T没有可访问的默认值,则将初始化不正确 构造函数);
  • 如果T是没有用户提供的构造函数的(可能是CV的)非工会类类型,则该对象 是零启动化的,如果T隐式宣布默认构造函数是非平凡的,则该构造函数为 称为。
  • ...
  • 否则,该对象为零。

8.5 [dcl.init]/5:

to 零initialize 类型T的对象或引用是:

...

  • 如果T是(可能是CV合格的)联合类型,则该对象的第一个非静态数据成员为零initialized 填充物初始化为零位;

从这些引用中,您可以看到,使用{}来初始化data会导致对象进行价值键化(因为SomeData是具有默认构造函数的类类型)。

没有用户提供的默认构造函数( SomeData为)的价值限制的联合表示零限制。

最后,零启动联合意味着零分化其第一个非静态数据成员。

整个联合将被归零。更确切地说,联盟的第一个成员将默认初始化,并且联盟中的所有剩余字节将设置为0,为 padding

参考(强调我的):

8.5初始化器[dcl.init]
...

5 to Zero Initialize type t type t type ty类型:
...
- 如果t是(可能是CV合格的)联合类型,则该对象的第一个非静态数据成员是零初始化和填充物初始化为零位;

这意味着联盟的第一个成员(此处std::uint8_t Byte;)将初始化为0,并且联盟中的所有其他字节将设置为0,因为它们是填充字节。


谨慎。如Angew "填充"所述。在标准中非常明确地指定,C编译器可以解释一下,工会中的填充字节仅是跟随最大成员的字节。我真的会发现很奇怪,因为兼容性更改是专门记录的,并且先前的版本(c)首先将所有内容初始化为0,而下一个则进行了特定的初始化。但是新的实施者无法意识到这一点...

tl/dr:我真的认为标准的目的是,联盟中的所有字节都设置为OP的示例中的0,但是对于任务关键程序,我肯定会添加一个明确的0构造函数...