2016-03-22 3 views
1

К сожалению, описание конкретного поведения Unions in C в онлайн-ресурсах (я могу перечислить несколько, если требуется), значительно отличается от одного источника к другому, а в некоторых случаях недостаточно. Один из ресурсов говорит: You can define a union with many members, but only one member can contain a value at any given time. и вот об этом. А потом еще один ресурс, говорит, in union, the only member whose value is currently stored will have the memory. Итак, теперь, если я запускаю эту программу,Совместное использование памяти для объединений в C

#include <stdio.h> 

union item 
{ 
int a; 
float b; 
char ch; 
}; 

int main() 
{ 
union item it; 
it.a = 12; 
it.b = 20.2; 
it.ch='z'; 
printf("%d\n",it.a); 
printf("%f\n",it.b); 
printf("%c\n",it.ch); 
return 0; 
} 

я получаю выход как:

1101109626 
20.199940 
z 

Интернет-сайт утверждает, что и б оба поврежден, хотя я немного не согласен здесь, так как b близок к 20.2. Во всяком случае, теперь, если я пишу char в начале, а затем пишу a и b (все тот же формат), я вижу, что b имеет правильное значение, но другие два повреждены. Однако, если я объявляю b как int, a и b оба правильные. Поэтому я выводю, что если члены союза имеют одинаковый формат, тогда, когда вы пишете какой-либо один член, остальные члены WILL содержат одинаковое значение (поскольку они имеют одинаковый формат), которые вы можете читать в любое время без любая проблема. Но если они все разные, то тот, который был написан последним, является только действительным значением. Я не нашел онлайн-ресурса, в котором говорится об этом категорически. Правильно ли это предположение?

+0

Если союз будет иметь ту же семантику, что и 'struct', это было бы бесполезно, не так ли? – Olaf

+1

c также поврежден, но в случае float litle-endiann может быть только дробная часть и может содержать только младший 8 бит. Поплавок IEEE-32Bit имеет 24 битовых бинарных знака, поэтому вы можете иметь относительную ошибку 2^24/2^8 = 2^-16 = 1.5e-5 – 12431234123412341234123

ответ

4

Но если они все различного формата, то тот, который был написан last, является действительным значением.

Вы почти правы.


Когда вы пишете один из членов союза и прочитать другой (тот, который не был записан в прошлом), то поведение не определено, которое может быть представление ловушкой.

С одной сноски проекта C11 n1570 (см сноской 95 в 6.5.2.3):

Если член используется для считывания содержимого объекта союза не же как член использовался в последний раз для сохранения значения в объекте подходящей частью представления объекта значения является , переинтерпретированное как представление объекта в новом типе, как описано в 6.2.6 (процесс, иногда называемый «type punning»). Это может быть представление ловушки.

+2

Это значительно облегчает. Благодаря тонну. Поскольку вы ответили первым, и правильно, я бы отметил его как принятый. Еще раз спасибо. – Semantics

3

Вся идея C union состоит в том, чтобы совместно использовать одну и ту же область хранения для разных типов. Если бы все члены союза имели один и тот же тип, тогда было бы бессмысленно иметь союз, потому что он был бы равен одному экземпляру этого типа для всех целей.

Союзы могут помочь вам достичь type punning, то есть «сырого» преобразования между различными типами, но поведение следует рассматривать как UB и зависит от платформы и компилятора. Иногда это поведение именно то, что вы хотите: например, вы можете захотеть получить собственное представление 32-разрядного float, преобразованного в 32-разрядное целое, или обработать структуру из двух 32-разрядных целых чисел в виде объединения с одним 64-разрядным целым для выполнения 64-битной арифметики и все еще имеют простой доступ к высоким и низким словам.

Вообще говоря, вы захотите использовать его для экономии места, когда вам нужно хранить значение определенного типа в любой момент. И имейте в виду, что вы можете иметь объединение любой комбинации struct s, а также не только примитивные типы, и пространство памяти будет эффективно использовано; union будет иметь размер самой большой структуры.

+2

Я бы добавил, что это часто используется в коде связи (например, вы получаете массив байтов, который вы переинтерпретируете в соответствии с форматом сообщений с CRC, длиной MSG, байтами данных и т. Д.). Но вы должны быть осторожны, что реинтерпретация по крайней мере имеет тот же размер, что и вы. – CodeMonkey

+0

Тип punning через union определен семантикой точно в той мере, в какой определены представления членов и что эти представления перекрываются. Когда рассматриваемые члены представляют собой структуры с одинаковой начальной последовательностью членов, доступ к этим общим членам полностью определяется. –

0

«Вы можете определить объединение со многими членами, но только один член может содержать значение в любой момент времени». является выражением corect.

Размер союза - это размер его наибольшего члена (плюс, возможно, некоторое заполнение). Использование члена инструктирует компилятор использовать тип этого элемента.

struct example { 
     int what_is_in_it; 
     union { 
      int a; 
      long b; 
      float f; 
     } u; 
} e; 

#define ITHASANINT  1 
#define ITHASALONG  2 
#define ITHASAFLOAT 3 

switch (e.what_is_in_it) { 
     case ITHASANINT: printf("%d\n", e.u.a); break; // compiler passes an int 
     case ITHASALONG: printf("%ld\n", e.u.b); break; // compiler passes a long 
     case ITHASAFLOAT:printf("%f\n", e.u.f); break; // compiler passes a float (promoted to double) 
} 
+0

Я считаю, что профсоюзам разрешено иметь заднюю прокладку, чтобы размер мог быть больше, чем размер наибольшего члена. В любом случае спецификации для 'sizeof' в C2011 6.5.3.4/4, похоже, так говорят.Реализация могла бы, например, заполнить все представления объединения, чтобы иметь размеры, кратные, скажем, 8 байтам. –

+0

@ Джон Боллинджер, спасибо. Обновлен мой ответ. –

2

Поскольку комментарии и другие ответы объяснить, цель союза (и структуры), чтобы позволить для составных типов переменных, а в случае союза конкретно, чтобы разделять память между членами. Имеет смысл, что только один член в любой момент владеет памятью, выделенной для объединения. Если случайно, после того, как одному члену было присвоено значение, но другой член, похоже, сохранил свое ранее присвоенное значение, это просто случайно, и его следует считать неопределенным (или неуказанным). Проще говоря, не полагайтесь на него.

Веб ссылки иногда нормально для предоставления дополнительного insignt, но вот некоторые из того, что говорит стандарт C на тему:

C99 6.2.5.20

тип союза описывает перекрытие непустой набор объектов-членов, , каждый из которых имеет опционально указанное имя и, возможно, отдельный тип .

Несколько строк вниз: C99 6.2.6.1.7

Когда значение хранится в элементе объекта типа союза, байт представления объекта, что делать не соответствуют этому участник, но они соответствуют другим членам, принимают неуказанные значения.

Смежные вопросы