Дополнительный пробел, используемый y
, который не используется x
, не считается заполнением. Раздел 6.7.2.1p17 стандарта C11 относительно состояний "Спецификаторы структуры и объединения":
Там может быть безымянный отступ в конце структуры или объединения
Байты, используемые y
в вашем примере, которые не используются x
, по-прежнему имеют имена и, следовательно, не дополняются.
В вашем примере, скорее всего, имеет этот безымянный заполнитель, так как самый большой элемент занимает 6 байтов, но один из членов - uint32_t
, который обычно требует выравнивания 4 байтов. На самом деле, на gcc 4.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, соответствующие
x
(то есть первому названному элементу), инициализируются равными 0, в результате чего x
равно 0.
- Байты 4 - 5, соответствующие y [2], остаются неинициализированными и имеют неопределенных значений .
- Байты 6 - 7, соответствующие заполнению, инициализируются равными 0.
Я протестировал это на gcc 4.8.5, clang 3.3 и MSVC 2015, и все они установили все байтов в 0 при различных настройках оптимизации. Однако при строгом чтении стандарта поведение не гарантируется, поэтому все же возможно, что разные настройки оптимизации этих компиляторов, разных версий или разных компиляторов могут сделать что-то другое.
С прагматической точки зрения для компилятора имеет смысл просто установить все байты статического объекта в 0, чтобы удовлетворить это требование. Это, конечно, при условии, что целочисленные типы не имеют отступов, типы с плавающей точкой - IEEE754, а указатели NULL имеют числовое значение 0. В большинстве систем, с которыми может столкнуться большинство людей, это будет иметь место. Системы, в которых это не так, могут с большей вероятностью оставить для этих байтов значение, отличное от 0. Итак, хотя эти байты могут быть установлены в 0, гарантии нет.
Важно помнить, что профсоюз может хранить только одного члена за раз согласно 6.7.2.1p16:
Размер союза достаточен, чтобы вместить самого большого из его членов. Значение в
большинство из членов могут быть сохранены в объекте объединения в любое время. Указатель на
Объект объединения, соответствующим образом преобразованный, указывает на каждого из его членов (или, если член
поле, затем к единице, в которой он находится), и наоборот.
Таким образом, если union
со статической продолжительностью хранения неинициализирован, доступ только к первому члену *1056* безопасен, так как это тот, который был неявно инициализирован.
Единственное исключение из этого, если объединение содержит структуры с общим набором начальных членов, и в этом случае вы можете получить доступ к любому из общих элементов внутренних структур. Это подробно описано в разделе 6.5.2.3p6:
Одна специальная гарантия сделана для того, чтобы упростить использование союзов: если союз содержит
несколько структур, которые имеют общую начальную последовательность (см. ниже), и если объединение
В настоящее время объект содержит одну из этих структур, разрешается проверять общие
Начальная часть любого из них где угодно, что объявление о завершенном типе объединения
виден Две структуры разделяют
общая начальная последовательность
если соответствующие члены
иметь совместимые типы (и, для битовых полей, одинаковой ширины) для последовательности из одного или нескольких
первоначальные члены.