Нулевая инициализация структур, гарантирующих протирание заполненных областей?

Предположим, что у меня есть следующая структура:

typedef struct { unsigned field1 :1; unsigned field2 :1; unsigned field3 :1; } mytype; 

Первые 3 бита будут использоваться, но sizeof(mytype) вернет 4 что означает 29 бит заполнения. Мой вопрос заключается в том, что эти биты заполнения, гарантированные стандартом, равны нулю, инициализируются оператором:

 mytype testfields = {0}; 

или же:

 mytype myfields = {1, 1, 1}; 

Таким образом, можно безопасно выполнить следующую memcmp() при условии, что бит 4..29 будет равен нулю и, следовательно, не повлияет на сравнение:

 if ( memcmp(&myfields, &testfields, sizeof(myfields)) == 0 ) printf("Fields have no bits set\n"); else printf("Fields have bits set\n"); 

И да и нет. Фактический стандарт C11 указывает:

Если объект, который имеет статическую или длительность хранения streamов, не инициализируется явно, то:

  • ….

  • если он является агрегатом, каждый элемент инициализируется (рекурсивно) в соответствии с этими правилами, и любое дополнение дополняется нулевыми битами;

Так что это справедливо только для объектов статического хранилища на первом представлении. Но потом он говорит дополнительно:

Если в списке, заключенном в скобках, меньше инициализаторов, чем в элементе или элементах совокупности или меньше символов в строковом литерале, используемом для инициализации массива с известным размером, чем в массиве, остальная часть совокупности должна неявно инициализируется тем же, что и объекты, имеющие статическую продолжительность хранения.

Таким образом, это означает, что заполнение внутри подструктур, которые не инициализированы явно, инициализируется нулевым битом.

В обобщении некоторые дополнения в структуре гарантированно инициализируются нулевым битом, некоторые – нет. Я не думаю, что такая путаница преднамеренно, я напишу отчет об ошибке.

У старых версий этого не было. Поэтому с большинством существующих компиляторов вы должны быть еще более осторожными, так как они еще не реализуют C11. Но AFAIR, clang уже делает от этого имени.

Также имейте в виду, что это выполняется только для инициализации. Заполнение не обязательно копируется при назначении.

В стандарте C99 не указывается, что биты заполнения будут установлены на ноль. Фактически, в нем конкретно упоминается, что значения любых дополняющих битов не определены, поэтому заполнение не нужно копировать в присваивании.

Сноска 51-6.2.6.1 (6) (n1570):

Таким образом, например, назначение структуры не должно копировать любые биты заполнения.

Новый стандарт C2011 – благодаря Jens Gustedt для обмена этими знаниями – указывает, что биты заполнения в объектах статической или продолжительности хранения streamов без явной инициализации инициализируются до 0.

По-прежнему нет гарантий для назначения.

Мой вопрос заключается в том, что эти биты заполнения, гарантированные стандартом, равны нулю, инициализируются оператором:

Нет.

Значение отступов неуказано:

(C99, 6.2.6.1p6) «Когда значение хранится в объекте структуры или типа объединения, в том числе в объекте-члене, байты представления объекта, которые соответствуют любым байтам заполнения, принимают неопределенные значения»

EDIT: см. Ответ Jens Gustedt, C11 теперь гарантирует, что заполнение установлено на 0 в (редких) определенных обстоятельствах