Никак не могу найти однозначный ответ на следующий вопрос.
Сколько себя помню, union
-ы всегда использовались не столько для поочередного хранения разных данных в одном месте, сколько для гибкого доступа к некоторым кускам этих самых данных. Иначе говоря, для записи данных одного типа и чтения данных другого типа.
Например:
typedef union u_color_pack
{
uint8_t b[4];
uint32_t raw;
} color_pack;
// …
uint8_t color_check(const uint32_t _raw)
{
color_pack color;
color.raw = _raw;
if (color.b[0] == 0)
{
return 0;
}
return 1;
}
color_pack
позволяет работать с цветом как с сырыми данными типа uint32_t
или же напрямую обращаться к отдельным байтам (цветам). Да, я понимаю, что приведенный код зависит от порядка байтов, но такой код обычно пишется с расчетом на строго определенный порядок байтов.
Так вот, проблема в том, что некоторые говорят, что нельзя читать из union
-а данные типа A
, если перед этим в union
были записаны данные типа B
.
Одни говорят, что такая ситуация является неопределенным поведением. Другие - что это поведение, определяемое реализацией.
Что по этой проблеме говорят стандарты C
и C++
? Отличается ли то, что они говорят?
Задача обращатся по одному адресу к данным и как к целой структуре и как к массиву байт - очень часто-встречаемая задача.
из комментариев от VTT, что б избежать UB следует делать так.
uint8_t color_check(const uint32_t _raw)
{
uint_8_t * b = reinterpret_cast<uint8_t *>(&raw)
if (b[0] == 0)
{
return 0;
}
return 1;
}
Не следует делать через
((char*)&_raw)[0]
- можно поймать UB.Про порядок байт - порядок байт может меняться, только если используются нестандартные платформы, т.е. если вы предполагаете, что код будет работать на платформах отличных от intel x86/x64-совместимых (или там AMD). Для ускорения вычислений - делают предопределение #define
и назначают значение предпроцессору, например
#ifdef litte_indian
// Прямой порядок
#else
// Обратный порядок
#endif
Теперь касательно стандартов.
На счёт UB https://habr.com/ru/post/216189/ п 1.3.12
Неопределенное поведение (undefined behavior)– поведение, которое может возникать в результате использования ошибочных программных конструкций или некорректных данных, на которые Международный Стандарт не налагает никаких требований. Неопределенное поведение также может возникать в ситуациях, не описанных в Стандарте явно.
На счёт использования union, стандарт с
не оговаривает как правильно использовать юнион, а стандарт c++
вам уже ответили VTT п 12.3
В с++ union в любой момент времени может быть активно не более одного поля. За исключением доступа к общей подструктуре standard-layout объектов, доступ к неактивным полям является неопределенным поведением. В общем случае для обращения к неактивному полю сначала следует вручную вызвать деструктор активного поля, затем вызвать placement new поля, которое требуется сделать активным.
В С++ в union в любой момент времени может быть активно не более одного поля. За исключением доступа к общей подструктуре standard-layout объектов, доступ к неактивным полям является неопределенным поведением. В общем случае для обращения к неактивному полю сначала следует вручную вызвать деструктор активного поля, затем вызвать placement new поля, которое требуется сделать активным.
12.3 Unions [class.union]
1 In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended (6.8). At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union
contains several standard-layout structs that share a common initial sequence (12.2), and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of the standard-layout struct members; see 12.2. —end note ]
Виртуальный выделенный сервер (VDS) становится отличным выбором
При выполнении GetOpenFileName иногда крашит программу с ошибкой: