Безопасно ли memset bool до 0?

Предположим, что у меня есть код legacy, который нельзя изменить, если обнаружена ошибка, и он содержит этот код:

bool data[32];
memset(data, 0, sizeof(data));

Является ли это безопасным способом установить для всех bool в массиве значение false?

В целом, безопасно ли memset a bool - 0, чтобы сделать его значение false?

Гарантируется ли работа над всеми компиляторами? Или я могу запросить исправление?

Ответ 1

Я считаю, что это неуказано, хотя, по-видимому, базовым представлением false будет все нули. Boost.Container полагается на это также (внимание мое):

Boost.Container использует std:: memset с нулевым значением для инициализации некоторых как в большинстве платформ, эта инициализация дает желаемый инициализация значения с улучшенной производительностью.

Следуя стандарту C11, Boost.Container предполагает, что для любого целочисленный тип, представление объекта, где все биты равны нулю должно быть представлением нулевого значения в этом типе. С _Bool/wchar_t/char16_t/char32_t также являются целыми типами в C, он рассматривает все интегральные типы С++ как инициализированные через std:: memset.

Эта цитата из C11, на которую они указывают, в качестве обоснования, фактически исходит из дефекта C99: дефект 263: представления с нулевыми битами, которые добавили следующее:

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

Итак, тогда вопрос заключается в правильности предположения, являются ли исходные представления объектов целыми, совместимыми между C и С++? Предложение Разрешение разницы между C и С++ в отношении представления объектов целыми числами пыталось ответить на это до некоторой степени, насколько я могу судить не разрешено. Я не могу найти убедительных доказательств этого в проекте стандарта. У нас есть пара случаев, когда он напрямую ссылается на стандарт C в отношении типов. Раздел 3.9.1 [basic.fundamental] говорит:

[...] Подписанные и беззнаковые целые типы должны удовлетворять ограничения, указанные в стандарте C, раздел 5.2.4.2.1.

и 3.9 [basic.types], который гласит:

Объектное представление объекта типа T является последовательностью N unsigned char объекты, занятые объектом типа T, где N равно SizeOf (Т). Представление значения объекта - это набор бит которые сохраняют значение типа Т. Для тривиально копируемых типов значение Представление представляет собой набор бит в представлении объекта, который определяет значение, которое является одним дискретным элементом определенный реализацией набор значений. 44

где сноска 44 (которая не является нормативной) говорит:

Предполагается, что модель памяти С++ совместима с моделью памяти ISO/IEC 9899 Язык программирования C.

Самый дальний проект стандарта получает указание базового представления bool в разделе 3.9.1:

Типы bool, char, char16_t, char32_t, wchar_t, а также подписанные и беззнаковые целочисленные типы совместно называются интегральными типами. 50 A Синоним интегрального типа - целочисленный. Представления интегральные типы должны определять значения с помощью чистой двоичной нумерации system.51 [Пример: этот международный стандарт разрешает 2 с дополнением, дополнением 1s и подписью величин для интегральные типы. -end пример]

в разделе также говорится:

Значения типа bool являются либо истинными, либо ложными.

но все, что мы знаем о true и false:

Булевы литералы являются ключевыми словами ложными и истинными. Такие литералы являются prvalues ​​и имеют тип bool.

и мы знаем, что они конвертируются в 0 an 1:

Значение класса bool может быть преобразовано в prvalue типа int, с false становится нулевым и истинным становится единым.

но это не приближает нас к базовому представлению.

Насколько я могу сказать, единственное место, где стандартная ссылка, фактическое базовое значение бита, кроме битов дополнений, была удалена через отчет о дефекте 1796: Все биты -zero для нулевых символов - значимое требование?:

Непонятно, что переносная программа может проверять биты представления; вместо этого он, по-видимому, будет ограничен изучением битов чисел, соответствующих представлению значений (3.9.1 [basic.fundamental], пункт 1). Возможно, более уместно потребовать, чтобы значение нулевого символа сравнивалось с 0 или "\ 0", а не указывало битовый шаблон представления.

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

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

Ответ 2

Гарантируется ли это законом? Нет.

С++ ничего не говорит о представлении значений bool.

Гарантируется ли она практической реальностью? Да.

Я имею в виду, если вы хотите найти реализацию С++, которая не представляет логическое false как последовательность нулей, я желаю вам удачи. Учитывая, что false должен неявно преобразовывать в 0, а true должен неявно преобразовывать в 1, а 0 должен неявно преобразовывать в false, а не 0 должен неявно преобразовывать в true & hellip; ну, вам было бы глупо реализовывать его любым другим способом.

Означает ли это, что это "безопасно" для вас.

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

Ответ 3

Нет. Это не безопасно (или, более конкретно, переносимо). Однако это, вероятно, работает в силу того факта, что ваша типичная реализация будет:

  • используйте 0 для представления логического значения (на самом деле это требует спецификация С++)
  • сгенерировать массив элементов, с которыми может работать memset().

Однако наилучшая практика будет диктовать использование bool data[32] = {false} - кроме того, это, скорее всего, освободит компилятор, чтобы внутренне представлять структуру по-разному - поскольку использование memset() может привести к созданию 32-байтового массива значений, а не, скажем, один 4 байта, который будет хорошо вписываться в ваш средний регистр CPU.

Ответ 4

Из 3.9.1/7:

Типы bool, char, char16_t, char32_t, wchar_t, а также подписанные и беззнаковые целые типы совместно называются интегральными типами. Синоним интегрального типа - целочисленный. Представления интегральные типы должны определять значения с помощью чистой двоичной нумерации система.

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