Гарантируется ли, что биты заполнения "обнуленной" структуры будут обнулены в C? - PullRequest
0 голосов
/ 07 октября 2018

Это утверждение в статье меня смутило:

C позволяет реализации вставлять заполнение в структуры (но не в массивы), чтобы гарантировать, что все поля имеют полезнуювыравнивание для цели. Если вы обнуляете структуру, а затем устанавливаете некоторые поля, все ли биты заполнения будут равны нулю? Согласно результатам опроса, 36 процентов были уверены, что они будут, а 29 процентов - нет.знать.В зависимости от компилятора (и уровня оптимизации), может быть или не быть .

Это было не совсем понятно, поэтому я обратился к стандарту. ИСО / МЭК 9899 в §6.2.6.1 гласит:

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

Также в §6.7.2.1 :

Порядок распределения битовых полей в блоке (от старшего к младшему или от младшего к старшему) определяется реализацией.Выравнивание адресуемой единицы хранения не определено.

Я только что вспомнил, что недавно реализовал, скажем, своего рода хак, где я использовал необъявленную часть байта, принадлежащую битовому полю.Это было что-то вроде:

/* This struct is always allocated on the heap and is zeroed. */
struct some_struct {
  /* initial part ... */
  enum {
    ONE,
    TWO,
    THREE,
    FOUR,
  } some_enum:8;
  unsigned char flag:1;
  unsigned char another_flag:1;
  unsigned int size_of_smth;
  /* ... remaining part */
};

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

unsigned char *ptr = &some->size_of_smth - 1;
*ptr |= 0xC0; /* set flags */

Затем позже я проверил флаги таким же образом.

Также я должен упомянуть, что целевой компилятор и платформа были определены, поэтому это не таккроссплатформенная вещь.Тем не менее, текущие вопросы по-прежнему имеют место:

  1. Могу ли я рассчитывать на то, что биты заполнения структуры (в куче) будут по-прежнему обнуляться после memset / kzalloc/ что-нибудь и некоторые используют?( Этот пост не раскрывает тему в терминах стандарта и мер безопасности для дальнейшего использования struct).А как насчет структуры, обнуленной в стеке, такой как = {0}?

  2. Если да, значит ли это, что я могу безопасно использовать «неназванную» / «не объявленную» часть битового поля для передачинемного информации для моих целей везде (разные платформы, компилятор, ..) в C?(Если я точно знаю, что ни один сумасшедший не пытается что-то сохранить в этом байте).

Ответы [ 3 ]

0 голосов
/ 07 октября 2018

Короткий ответ на ваш первый вопрос - «нет».

Хотя соответствующий вызов memset(), такой как memset(&some_struct_instance, 0, sizeof(some_struct)), установит все байты в структуре на ноль, это изменение не обязательно должно быть постоянным после «некоторого использования» some_struct_instance, такого какустановка любого из членов внутри него.

Так, например, нет гарантии, что some_struct_instance.some_enum = THREE (то есть сохранение значения в элементе) оставит любые биты заполнения в some_struct_instance неизменными.Единственным требованием в стандарте является то, что значения других членов структуры не затрагиваются.Однако компилятор может (в передаваемом объектном коде или машинных инструкциях) реализовать назначение, используя некоторый набор побитовых операций, и ему разрешено использовать ярлыки таким образом, чтобы не оставлять биты заполнения в одиночку (например, не испуская команды, которые могли быв противном случае убедитесь, что биты заполнения не затронуты).

Еще хуже, простое присвоение, подобное some_struct_instance = some_other_struct_instance (которое по определению является сохранением значения в some_struct_instance), не дает никаких гарантий относительно значенийбиты заполнения.Не гарантируется, что биты заполнения в some_struct_instance будут установлены в те же битовые значения, что и биты заполнения в some_other_struct_instance, и нет гарантии того, что биты заполнения в some_struct_instance не будут изменены.Это связано с тем, что компилятору разрешено реализовывать присваивание любым способом, который он считает наиболее «эффективным» (например, дословное копирование памяти, некоторый набор присваиваемых элементам присваиваний или что-либо еще), но - поскольку значение битов заполнения после присвоения не указано- не требуется, чтобы гарантировать, что биты дополнения неизменны.

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

Поскольку ответ на ваш первый вопрос - «нет», нет необходимости отвечать на ваш второй вопрос.Однако с философской точки зрения, если вы пытаетесь сохранить данные в битах заполнения структуры, разумно утверждать, что кто-то еще - сумасшедший или нет - может потенциально попытаться сделать то же самоевещь, но используя подход, который портит данные, которые вы пытаетесь обойти.

0 голосов
/ 07 октября 2018

С первых слов стандартной спецификации:

C позволяет реализации вставлять заполнение в структуры (но не в массивы), чтобы гарантировать, что все поля имеют полезное выравнивание ...

Эти слова означают, что в целях оптимизации (возможно, оптимизации по скорости, но также во избежание архитектурных ограничений на шины данных / адресов) компилятор может использовать скрытые, неиспользуемые битыили байты.НЕ ИСПОЛЬЗУЕТСЯ, потому что их было бы запрещено или дорого для адресации.

Это также означает, что эти байты или биты не должны быть видны с точки зрения программирования, и это должно рассматриваться как ошибка программирования, чтобы попытаться получить доступ к этим скрытымdata.

Об этих добавленных данных в стандарте говорится, что их содержимое "не указано", и в действительности нет лучшего способа указать, что реализация может с ними сделать.Подумайте о тех объявлениях битовых полей, где вы можете объявить целые числа с любой битовой шириной: никакое обычное оборудование не позволит читать / писать из памяти кусками, меньшими, чем 8 бит, поэтому ЦП всегда будет читать или записывать по крайней мере 8 бит (иногда дажеБольше).Почему компилятор (реализация) должен позаботиться о том, чтобы сделать что-то полезное для тех других битов, которые, как указал программист, ему безразличны?Это не имеет смысла: программист не дал имя некоторому адресу памяти, но затем он хочет манипулировать им?

Байты заполнения между полями почти такие же, как и раньше: эти добавленные байтынеобходимо, но программист не заинтересован в них - и он НЕ ДОЛЖЕН передумать позже!

Конечно, можно изучить реализацию и прийти к какому-либо заключению типа «заполненные байты всегда будут обнуляться» или что-то в этом роде.как это.Это рискованно (вы уверены, что они всегда будут всегда обнуляться?), Но, что более важно, это абсолютно бесполезно: если вам нужно больше данных в структуре, просто объявите их!И у вас никогда не возникнет проблем, даже если вы перенесете исходный код на разные платформы или реализации.

0 голосов
/ 07 октября 2018

Разумно начинать с того, что то, что перечислено в стандарте, правильно реализовано.Вы ищете дополнительные гарантии для конкретной архитектуры.Лично, если бы я мог найти документированные детали об этой конкретной архитектуре, я был бы уверен;в противном случае я был бы осторожен.

То, что составляло "осторожность", зависело бы от того, насколько я был уверен в себе.Например, создание подробного набора тестов и его периодическое выполнение на моей целевой архитектуре даст мне разумную степень уверенности, но все зависит от того, какой риск вы хотите взять.Если это действительно очень важно, придерживайтесь того, что вам гарантируют стандарты;если это не так, проверьте и посмотрите, сможете ли вы получить достаточно уверенности в том, что вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...