как лучше всего скопировать профсоюз, крупнейший член которого неизвестен

#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 .