Является ли это memset-memcmp для структурной переменной допустимым C?
Законно ли это memset
структура к некоторому значению, затем сравните его с memcmp
?
struct S {
// struct definition not relevant, but it has bitfields
};
struct S invalid_S;
memset(&invalid_S, 0xFF, sizeof invalid_S);
struct S value;
memset(&value, 0, sizeof value); // actual data read would be here
if (memcmp(&invalid_S, &value, sizeof(struct S) != 0) {
/// operate on fields of value
}
struct S value2;
value2 = invalid_S;
if (memcmp(&invalid_S, &value2, sizeof(struct S) != 0) {
/// operate on fields of value, which doesn't happen now
}
Является ли приведенное выше поведение кодов хорошо определенным, неопределенным или зависящим от реализации? Зависит ли достоверность вышеуказанного кода от struct S
?
Причина, по которой структура заполнена 0xFF, а затем сравнивается с memcmp
, это: у меня есть функция, которая возвращает структуру битового поля, которая соответствует тому, что я прочитал с аппаратного устройства, без потраченных битов или байтов, и я хочу эффективный способ сообщить об ошибке (устройство никогда не сможет вернуть все байты 0xFF). У меня есть фиксированные платформы и наборы инструментов, где код работает сейчас, но могу ли я верить, что он не сломается, если я, например, увеличу уровень оптимизации?
Вердикт: хотя этот код можно было заставить работать, если бы я удостоверился, что нет битов заполнения, полей с плавающей запятой и т. Д., Возможно, проблематично, я решил вместо этого просто установить одно конкретное поле структуры на определенное "невозможное" значение, чтобы указать ошибку.
2 ответа
Допустимо ли для memset задавать какое-либо значение, а затем сравнивать его с memcmp?
Да, поскольку все memset, memcmp, memcpy задокументированы для работы в произвольных зонах памяти (при условии, что указатель и передаваемый им размер указывают на допустимую зону памяти).
Однако в некоторых случаях это может не иметь смысла. Например, если вы memcpy
из некоторой неинициализированной памяти вы получите мусор в месте назначения, и использование этого мусора может быть неопределенным поведением.
Ты используешь memset
с 0xff
, Теоретически, у вас могут быть некоторые реализации, где char
больше 8 бит (но на практике этого не происходит, поэтому вам все равно).
В теории у вас может быть некоторая реализация, имеющая представления ловушек для целочисленного значения. На практике этого не происходит.
Если вы используете memcmp
на структурах, имеющих отступы, которые могут работать не так, как вы ожидаете. Возможно, вы захотите погрузиться в спецификацию ABI вашей платформы, чтобы понять, как они реализованы (а битовые поля могут не указываться в вашем ABI и зависеть от компилятора).
Я считаю, что на практике вы должны хорошо понимать точную компоновку вашего struct
с вашим конкретным компилятором. Похоже, что ваш код может зависеть от аппаратного обеспечения, тогда вас не волнует переносимость. Так что на практике ваш struct S
очень актуально (возможно, избегать битовых полей в нем было бы "безопаснее").
Вы говорите, что функция возвращает "структуру битового поля". Если вы действительно возвращаете структуру, то есть возвращаете структуру по значению, то нет, поведение не обязательно будет таким, как вы хотите. Когда структура копируется, реализация просто должна воспроизвести значения в ее членах, а не фактические байты в ее представлении.
То же самое относится к вашей линии value2 = invalid_S;
,