Разница между структурой и союзом

366

Есть ли хороший пример, чтобы дать разницу между struct и a union? В основном я знаю, что struct использует всю память своего члена, а union использует наибольшее пространство памяти членов. Есть ли другая разница в уровне ОС?

Теги:
struct
unions

15 ответов

642
Лучший ответ

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

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

union foo {
  int a;   // can't use both a and b at once
  char b;
} foo;

struct bar {
  int a;   // can use both a and b simultaneously
  char b;
} bar;

union foo x;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!

struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK

edit: Если вам интересно, какая настройка xb в 'c' изменяет значение xa на, с технической точки зрения это не определено. На большинстве современных машин символ равен 1 байту, а int - 4 байта, поэтому значение xb означает, что значение "c" также дает первый байт xa того же значения:

union foo x;
x.a = 3;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

печать

99, 99

Почему два значения одинаковы? Потому что последние 3 байта int 3 равны нулю, поэтому он также читается как 99. Если мы поместим большее число для xa, вы увидите, что это не всегда так:

union foo x;
x.a = 387439;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

печать

387427, 99

Чтобы более подробно ознакомиться с фактическими значениями памяти, задайте и распечатайте значения в шестнадцатеричном формате:

union foo x;
x.a = 0xDEADBEEF;
x.b = 0x22;
printf("%x, %x\n", x.a, x.b);

печать

deadbe22, 22

Вы можете четко видеть, где 0x22 перезаписал 0xEF.

НО

В C порядок байтов в int не определен. Эта программа перезаписала 0xEF с 0x22 на моем Mac, но есть и другие платформы, где она заменила бы 0xDE вместо этого, потому что порядок байтов, составляющих int, был отменен. Поэтому при написании программы вы никогда не должны полагаться на поведение перезаписи конкретных данных в объединении, поскольку оно не переносимо.

Для более чтений на упорядочении байт, проверить порядок байт.

  • 7
    спасибо, это дает очень четкий и хороший ответ. хороший пример, чтобы пройти ...
  • 0
    используя этот пример в union, если xb = 'c', что хранится в xa? это ссылка номер символа?
Показать ещё 14 комментариев
76

Здесь короткий ответ: структура - это структура записи: каждый элемент в структуре выделяет новое пространство. Итак, структура типа

struct foobarbazquux_t {
    int foo;
    long bar;
    double baz; 
    long double quux;
}

выделяет не менее (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) байтов в памяти для каждого экземпляра. ( "По крайней мере", потому что ограничения выравнивания архитектуры могут заставить компилятор вставить конструкцию.)

С другой стороны,

union foobarbazquux_u {
    int foo;
    long bar;
    double baz; 
    long double quux;
}

выделяет один кусок памяти и дает четыре псевдонима. Итак, sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)), опять же с возможностью некоторого добавления для выравниваний.

48

Есть ли хороший пример, чтобы дать разницу между "структурой" и "союзом"?

Мнимый протокол связи

struct packetheader {
   int sourceaddress;
   int destaddress;
   int messagetype;
   union request {
       char fourcc[4];
       int requestnumber;
   };
};

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

Профсоюзы в основном представляют собой низкоуровневые детали, основанные на наследии C как язык системного программирования, где иногда используются "перекрывающиеся" места хранения. Иногда вы можете использовать союзы для экономии памяти, где у вас есть структура данных, где только один из нескольких типов будет сохранен за один раз.

В общем, ОС не заботится и не знает о структурах и объединениях - они оба являются блоками памяти. Структура - это блок памяти, в котором хранятся несколько объектов данных, где эти объекты не перекрываются. Объединение представляет собой блок памяти, который хранит несколько объектов данных, но имеет только хранилище для самого большого из них и, таким образом, может хранить только один из объектов данных в любой момент времени.

  • 3
    Этот идеален :)
  • 1
    Ага. Это хорошо объясняет прецедент!
Показать ещё 2 комментария
39

Как вы уже сказали в своем вопросе, основное различие между union и struct заключается в том, что члены union накладывают память друг на друга, так что sizeof объединения является единственным, а struct членами выкладываются один за другим (с дополнительным дополнением между ними). Также союз достаточно велик, чтобы содержать всех его членов и иметь выравнивание, соответствующее всем его членам. Так что пусть int может храниться только на 2 байтовых адресах и имеет ширину 2 байта, а long может храниться только с 4 байтовыми адресами и длиной 4 байта. Следующее объединение

union test {
    int a;
    long b;
}; 

может иметь sizeof из 4 и требование выравнивания 4. И объединение, и структура могут иметь дополнение в конце, но не в начале. Запись в структуру меняет только значение члена, на который написано. Запись в член союза приведет к недействительности значения всех других членов. Вы не можете получить к ним доступ, если вы ранее не писали им, иначе поведение undefined. GCC предоставляет расширение, которое вы действительно можете прочитать от членов профсоюза, даже если вы не писали их совсем недавно. Для операционной системы не имеет значения, записывает ли пользовательская программа в объединение или в структуру. Это фактически проблема компилятора.

Другим важным свойством union и struct является то, что они позволяют указателю на них указывать на типы любого из его членов. Итак, справедливо следующее:

struct test {
    int a;
    double b;
} * some_test_pointer;

some_test_pointer может указывать на int* или bool*. Если вы укажете адрес типа test на int*, он будет указывать на его первый член, a, на самом деле. То же самое верно и для союза. Таким образом, поскольку союз всегда имеет правильное выравнивание, вы можете использовать объединение, чтобы указать на какой-либо тип:

union a {
    int a;
    double b;
};

Этот союз действительно сможет указать на int и double:

union a * v = (union a*)some_int_pointer;
*some_int_pointer = 5;
v->a = 10;
return *some_int_pointer;    

действительно действителен, как указано в стандарте C99:

Объект должен иметь сохраненное значение, к которому обращается только выражение lvalue, которое имеет один из следующих типов:

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

Компилятор не будет оптимизировать v->a = 10;, поскольку это может повлиять на значение *some_int_pointer (и функция вернет 10 вместо 5).

  • 1
    спасибо, объясняет многое из того, что мне было неясно!
  • 1
    Трудно поверить, что за этот ответ не проголосовали.
17

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

Примером этого является анализ числа float с помощью union a struct с битовыми полями и a float. Я сохраняю номер в float, а позже я могу получить доступ к определенным частям float через struct. В этом примере показано, как union используется для просмотра разных углов.

#include <stdio.h>                                                                                                                                       

union foo {
    struct float_guts {
        unsigned int fraction : 23;
        unsigned int exponent : 8;
        unsigned int sign     : 1;
    } fg;
    float f;
};

void print_float(float f) {
    union foo ff;
    ff.f = f;
    printf("%f: %d 0x%X 0x%X\n", f, ff.fg.sign, ff.fg.exponent, ff.fg.fraction);

}

int main(){
    print_float(0.15625);
    return 0;
}

Посмотрите одинарная точность на wikipedia. Я использовал пример и магический номер 0.15625 оттуда.


union также может использоваться для реализации алгебраического типа данных, который имеет несколько альтернатив. Я нашел пример этого в книге "Реальный мир Хаскелл" О'Салливана, Стюарта и Герцена. Проверьте это в разделе Разделенный раздел.

Ура!

11

Нетехнически означает:

Предположение: chair = блок памяти, people = variable

Структура. Если есть 3 человека, они могут сидеть в кресле своего размера соответственно.

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

Технически означает:

Нижеприведенная программа дает глубокое погружение в структуру и объединение вместе.

struct MAIN_STRUCT
{
UINT64 bufferaddr;   
union {
    UINT32 data;
    struct INNER_STRUCT{
        UINT16 length;  
        UINT8 cso;  
        UINT8 cmd;  
           } flags;
     } data1;
};

Total MAIN_STRUCT size = sizeof (UINT64) для bufferaddr + sizeof (UNIT32) для объединения + 32 бит для заполнения (зависит от архитектуры процессора) = 128 бит. Для структуры все члены получают блок памяти смежно.

Союз получает один блок памяти члена максимального размера (здесь его 32 бит). Внутри союза еще одна структура лежит (INNER_STRUCT), ее члены получают блок памяти общего размера 32 бита (16 + 8 + 8). В объединении могут быть доступны либо INNER_STRUCT (32-разрядный) член , либо данные (32 бит).

  • 0
    Отличное объяснение. Ура!
11

Да, основное различие между struct и union такое же, как вы заявили. Struct использует всю память своего члена, а объединение использует наибольшее пространство памяти членов.

Но вся разница заключается в необходимости использования памяти. Наилучшее использование объединения можно увидеть в процессах unix, где мы используем сигналы. как процесс может действовать только по одному сигналу за раз. Таким образом, общая декларация будет:

union SIGSELECT
{
  SIGNAL_1 signal1;
  SIGNAL_2 signal2;
  .....
};

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

Подводя итог, следует выбрать Union, если вы знаете, что вы обращаетесь к любому из членов за раз.

11

" union" и " struct" являются конструкциями языка C. Говорить о разнице в уровне ОС между ними нецелесообразно, так как это компилятор, который создает другой код, если вы используете одно или другое ключевое слово.

10

У вас есть это, все. Но так, в принципе, какой смысл профсоюзов?

Вы можете разместить одно и то же содержимое местоположения разных типов. Вы должны знать тип того, что вы сохранили в объединении (так часто вы помещаете его в struct с тегом типа...).

Почему это важно? Не совсем для космической выгоды. Да, вы можете получить некоторые бит или сделать некоторые дополнения, но это не главное.

Это для безопасности типов, это позволяет вам выполнять какую-то "динамическую типизацию": компилятор знает, что ваш контент может иметь разные значения и точное значение того, как ваша интерпретация зависит от вас во время выполнения. Если у вас есть указатель, который может указывать на разные типы, вы ДОЛЖНЫ использовать объединение, иначе код может быть некорректным из-за проблем с псевдонимом (компилятор говорит себе "о, только этот указатель может указывать на этот тип, поэтому я могу оптимизировать из этих доступов...", и могут произойти плохие вещи).

9

Структура распределяет общий размер всех элементов в ней.

Объединение выделяет столько памяти, сколько требует его наибольший член.

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

Использование союза Союзы часто используются, когда необходимы специализированные разговоры типов. Получить представление о пользе союза. Стандартная библиотека c/c не определяет функцию, специально предназначенную для записи коротких целых чисел в файл. Использование функции fwrite() приводит к чрезмерным накладным расходам для простой работы. Однако, используя объединение, вы можете легко создать функцию, которая записывает двоичный код короткого целого в файл по одному байту за раз. Я предполагаю, что короткие целые числа длиной 2 байта

ПРИМЕР:

#include<stdio.h>
union pw {
short int i;
char ch[2];
};
int putw(short int num, FILE *fp);
int main (void)
{
FILE *fp;
fp fopen("test.tmp", "wb ");
putw(1000, fp); /* write the value 1000 as an integer*/
fclose(fp);
return 0;
}
int putw(short int num, FILE *fp)
{
pw word;
word.i = num;
putc(word.c[0] , fp);
return putc(word.c[1] , fp);
}    

хотя putw(), который я назвал с коротким целым числом, можно было использовать putc() и fwrite(). Но я хотел показать пример, чтобы доминировать, как можно использовать союз

3
Структура

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

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

struct emp
{
    char x;//1 byte
    float y; //4 byte
} e;

полная память: get = > 5 байт

union emp
{
    char x;//1 byte
    float y; //4 byte
} e;

полная память: get = 4 байт

2

В чем разница между структурой и объединением?

Ответ на короткое замыкание: отношение к распределению памяти. Объяснение: В структуре пространство памяти будет создано для всех членов внутри структуры. В объединительной памяти пространство будет создано только для члена, которому требуется наибольшее пространство памяти. Рассмотрим следующий код:

struct s_tag
{
   int a; 
   long int b;
} x;

union u_tag
{
   int a; 
   long int b;
} y;

Здесь внутри структуры и объединения есть два члена: int и long int. Объем памяти для int равен: 4 байта, а пространство памяти для длинного int: 8 в 32-разрядной операционной системе.

Итак, для struct 4 + 8 = будет создано 12 байт, а для объединения будет создано 8 байт

Пример кода:

#include<stdio.h>
struct s_tag
{
  int a;
  long int b;
} x;
union u_tag
{
     int a;
     long int b;
} y;
int main()
{
    printf("Memory allocation for structure = %d", sizeof(x));
    printf("\nMemory allocation for union = %d", sizeof(y));
    return 0;
}

Ссылка: http://www.codingpractise.com/home/c-programming/structure-and-union/

1

Союз отличается от структуры, когда Союз повторяет другие: он переопределяет одну и ту же память, в то время как структура определяет один за другим без перекрытий или переопределений.

1

Союзы пригодится при написании функции упорядочения байтов, которая приведена ниже. Это невозможно с помощью структур.

int main(int argc, char **argv) {
    union {
        short   s;
        char    c[sizeof(short)];
    } un;

    un.s = 0x0102;

    if (sizeof(short) == 2) {
        if (un.c[0] == 1 && un.c[1] == 2)
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)
            printf("little-endian\n");
        else
            printf("unknown\n");
    } else
        printf("sizeof(short) = %d\n", sizeof(short));

    exit(0);
}
// Program from Unix Network Programming Vol. 1 by Stevens.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню