#c
Вопрос:
Вот структура на языке Си, она содержит один из нескольких типов данных, и мы не знаем, какие данные имеют наибольшее значение sizeof
:
typedef struct { union { void *p_data; size_t s_data; }; int extra_stuff; } data_and_stuff;
Теперь мне нужен наиболее эффективный способ копирования (любых) данных из одного экземпляра структуры в другой, например:
void copy_data(data_and_stuff *from, data_and_stuff *to) { to-gt;p_data = from-gt;p_data ; \ WRONG! }
Конечно, это неправильно, так как возможно sizeof(size_t) gt; sizeof(void *)
.
Использование препроцессора для определения имени самого большого члена не работает, так как я не могу его использовать sizeof()
.
Хорошо, я мог бы дать союзу имя, да (как предлагали комментаторы), но я не хочу этого делать, потому что тогда это имя будет использоваться во всех видах кода, это затруднит понимание всего кода.
Итак, вот что я придумал, довольно уродливо:
typedef struct { union { void *p_data; size_t s_data; union { void * p; size_t s; } largest_data; }; int extra_stuff; } data_and_stuff; void copy_data(data_and_stuff *from, data_and_stuff *to) { to-gt;largest_data = from-gt;largest_data ; }
Есть ли лучший способ?
РЕДАКТИРОВАТЬ: Я предполагаю, как прокомментировал Джон, что мой код не гарантируется стандартом для работы 🙂 . Я имею в виду, что он «должен», но в стандарте явно сказано, чтобы не читать одного члена союза после записи другому.
Комментарии:
1. Можете ли вы дать название анонимному союзу?
2. @dbush ну, на самом деле я этого не хочу, иначе мне это не нужно, и это усложнит разыменование. Допустим, я не хочу этого делать без крайней необходимости.
3. да, таким образом, вопрос должен быть, я хочу избежать имени, потому что оно будет использоваться в других случаях явно и поэтому излишне усложнит интерфейс
4. Поскольку союзы являются своего рода волшебством, вам либо нужно иметь что-то, что знает о типе союза для копирования, либо вам нужно запомнить весь союз, который, следовательно, должен быть назван.
5. @dbush спасибо, я думаю, что тогда все
Ответ №1:
Вот структура на языке Си, она содержит один из нескольких типов данных, и мы не знаем, какие данные имеют наибольшее значение
sizeof
Вопрос не в том, чтобы знать, у какого члена профсоюза самый большой размер. Вам нужно скопировать элемент, если таковой имеется, в котором на самом деле хранится значение, или весь союз (что вы не можете сделать, потому что он анонимный), или всю структуру.
Если вы не знаете, у какого члена союза хранится значение, то копирование всей структуры-ваш единственный допустимый вариант. К счастью, это очень легко выразить …
void copy_data(data_and_stuff *from, data_and_stuff *to) { *to = *from; }
… и компилятор, скорее всего, создаст код, который справится с этим довольно эффективно.
Комментарии:
1. Хорошо, но вы уверены, что то, что у меня есть выше, не работает?? Все члены профсоюза гарантированно будут согласованы в начале всего профсоюза. Так что то, что у меня есть, похоже
memcpy
, но без использования адресов.2. @MarkGaleck, я уверен, что код, представленный в вопросе, имеет неопределенное поведение, когда член
*from
анонимного союза, в котором хранится значение, им неlargest_data
является . Это не обязательно то же самое, что «не работает» (т. е. «не определено»), но это определенно подразумевает «не следует использовать».3. вы имеете в виду, что причина, по которой это не определено, заключается в том, что в стандарте есть такое понятие «активного» члена, как, например, не читать одного члена союза после письма другому ??
4. @MarkGaleck, Строгое правило псевдонимов (пункт 6.5/7 спецификации языка) запрещает большинство вариантов доступа к объекту с помощью типа, отличного от его эффективного типа, что, как я утверждаю, вы здесь рассматриваете. Я предполагаю, что может быть аргумент, что союз, скрывающийся под одеялом, решает эту проблему, но я не читаю спецификацию таким образом. Если вы заботитесь о переносимости и надежности, то было бы неразумно вешать шляпу на более разрешительную интерпретацию.
5. @JohnBollinger Что касается строгого псевдонима, вы можете «получить доступ к значению» к содержимому объединения, используя любой тип, присутствующий в этом объединении. C здесь более терпим, чем C .