Каков правильный способ передачи ценностей между профсоюзами?

R.Austin спросил: 28 марта 2018 в 02:28 в: c

Если у вас есть:

typedef union value {
    int i;
    float f;
} VALUE;
VALUE a, b;

, если вы знаете тип a, должны ли вы делать

b.i = a.i;
b.f = a.f;

или

if(a_type == INT)
    b.i = a.i;
if(a_type == FLOAT)
    b.f = a.f;

3 ответа

Eric Postpischil ответил: 28 марта 2018 в 02:46

Просто используйте b = a, если для этого нет особой причины, например, что объединение иногда содержит большой объем данных, и вы хотите оптимизировать назначение для случаев, когда оно содержит только небольшое количество .

В соответствии с C 2011 [N1570] 6.5.16.1 1, одна из допустимых ситуаций для простого присваивания:

левый операнд имеет атомарный, квалифицированный или неквалифицированный версия типа структуры или объединения, совместимая с типом права.

Согласно 6.2.7 1:

Два типа имеют совместимый тип, если их типы одинаковы.

(Согласно 6.2.6.1 6, "Значение объекта структуры или объединения никогда не является представлением ловушек, даже если значение члена структуры или объекта объединения может быть представлением ловушки.")

chqrlie ответил: 28 марта 2018 в 02:58
Определенно лучший ответ на хороший вопрос.
Pablo ответил: 28 марта 2018 в 04:54
Да, согласен, это хороший ответ
P__J__ ответил: 28 марта 2018 в 02:41

Наиболее правильным, вероятно, является (при условии, что тот же тип)

memcpy(&b, &a, sizeof(b));
Felix Palmen ответил: 28 марта 2018 в 02:33
правильно, предложите убрать круглые скобки вокруг b в качестве аргумента sizeof ... они понадобятся только для имени типа.
chqrlie ответил: 28 марта 2018 в 02:33
Что насчет b = a?
P__J__ ответил: 28 марта 2018 в 02:34
@FelixPalmen Они мне нравятся. Это мой стиль.
Felix Palmen ответил: 28 марта 2018 в 02:44
ну, да, типичный стиль для sizeof состоит в том, чтобы использовать один пробел, когда аргумент является выражением, и использовать паразиты без пробела, когда аргумент является именем типа. Но пиши что хочешь, если настаиваешь: D
chqrlie ответил: 28 марта 2018 в 02:48
@ PeterJ_01: вообще никаких опасностей. На самом деле безопаснее, если вы работаете где-то рядом с Линусом Торвальдсом: news.ycombinator.com/item?id=9629461
supercat ответил: 01 апреля 2018 в 06:11

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

objectOfMemberType = someUnion.member1;
someUnion.member1 = valueOfMemberType;

A quality у компилятора также не должно быть проблем с такими конструкциями, как:

memberType *p = &someUnion.member1;
*p = valueOfMemberType;

Поскольку стандарт написан, он не предъявляет никаких требований к поведению любой конструкции, если член имеет не символьный тип, и, таким образом, единственные способы сделать что-либо с объединениями без вызова UB - это либо использовать lvalue типа union для копирования всего содержимого объединения, либо использовать lvalue символьного типа для доступа к частям объединения, либо использовать такие функции, как memcpy. Доступ к содержимому объединения напрямую через lvalues-члены кажется в основном надежным в gcc и clang (я думаю, что случаи, которые я обнаружил, когда они не являются непреднамеренными ошибками), но ни gcc, ни clang не предназначены для надежной поддержки любого использования указателей на члены union , даже когда использование немедленно следует за захватом адреса [как показано выше].

Учитывая способ написания стандарта C, трудно действительно определить "правильный""способ передачи значений между объединениями, так как большинство видов кода, которые будут использовать объединения полезным образом, вызывают UB. Какой подход лучше всего, зависит от того, какие формы UB готовы доверять компилятору в разумной обработке.