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

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

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

Первые три бита будут использоваться, но 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");

Ответ 1

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

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

  • ....

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Нет.

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

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

РЕДАКТИРОВАТЬ: См. Jens Gustedt answer, теперь C11 гарантирует, что отступы установлены на 0 в (редких) определенных обстоятельствах