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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
434
0
362 749
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

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

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

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

Jim Buck 06.12.2008 21:01
Ответ принят как подходящий

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

Чтобы привести конкретный пример их использования, я некоторое время назад работал над интерпретатором схемы и фактически накладывал типы данных схемы на типы данных 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

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

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

отпечатки

99, 99

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

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, был изменен на обратный. Следовательно, при написании программы вы никогда не должны полагаться на поведение перезаписи определенных данных в объединении, потому что это непереносимо.

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

используя этот пример в объединении, если x.b = 'c', что сохраняется в x.a? это ссылка # символа?

kylex 06.12.2008 22:04

Надеюсь, это объясняет более подробно, что хранится в x.a, когда вы устанавливаете x.b.

Kyle Cronin 06.12.2008 22:33

Мне интересно, когда и зачем вам нужно использовать профсоюз. Кажется странным группировать вместе переменные, которые нельзя использовать вместе.

user12345613 21.02.2012 04:28

@ user12345613 Это полезно, если вы хотите хранить разные типы данных в одном месте. В своем ответе я упоминаю свой интерпретатор схемы - он должен был иметь возможность хранить различные типы атомарных данных в одном типе.

Kyle Cronin 21.02.2012 04:34

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

user12345613 21.02.2012 04:49

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

Morten Jensen 13.03.2013 01:57

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

SomethingSomething 23.12.2015 11:39

Куда пишет байт зависит от Endianess? @KyleCronin

user5585984 27.04.2016 11:18

@Lazar Порядок байтов в многобайтовых типах зависит от порядка байтов. Предлагаю прочитать об этом статью в Википедии.

Kyle Cronin 27.04.2016 21:11

@KyleCronin Правильно ли это думать об объединениях: для доступа ко всем четырем байтам данного фрагмента памяти используйте x.a, а для доступа только к последнему (или первому?) Байту используйте x.b? Тогда это означает, что поля объединения - это просто псевдонимы для ссылки на некоторую выбранную часть фрагмента памяти.

stillanoob 06.11.2016 16:45

@KyleCronin Целочисленное переполнение здесь? x.a = 387439;? 387439 больше, чем может вместить int, что вызывает неопределенное поведение, конечно, он будет вести себя иначе.

Undefined Behavior 12.01.2019 05:33

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

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

union test {
    int a;
    long b;
}; 

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

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

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

some_test_pointer может указывать на int* или double*. Если вы приведете адрес типа 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:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object
  • ...
  • an aggregate or union type that includes one of the aforementioned types among its members

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

Вот и все. Но в чем вообще смысл профсоюзов?

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

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

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

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

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)), опять же с возможностью некоторых дополнений для выравнивания.

Is there any good example to give the difference between a 'struct' and a 'union'?

Воображаемый протокол связи

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

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

Объединения в значительной степени представляют собой низкоуровневые детали, основанные на наследии C как языка системного программирования, где иногда таким образом используются «перекрывающиеся» места хранения. Иногда вы можете использовать объединения для экономии памяти, если у вас есть структура данных, в которой одновременно будет сохранен только один из нескольких типов.

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

Ага. Это хорошо объясняет вариант использования!

gideon 25.05.2013 16:49

Предположим, у вас есть packetheader ph;, как вы получаете доступ к номеру запроса? ph.request.requestnumber?

justin.m.chase 25.08.2015 05:14

Лучшее объяснение! Спасибо.

84RR1573R 23.10.2017 21:26

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

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

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

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

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

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

Примером этого является анализ числа float с использованием union из struct с битовыми полями и 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;
}

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


union также можно использовать для реализации алгебраического типа данных, имеющего несколько альтернатив. Я нашел пример этого в книге О'Салливана, Стюарта и Герцена «Real World Haskell». Посмотрите это в разделе Дискриминированный союз.

Ваше здоровье!

Объединения пригодятся при написании функции упорядочивания байтов, которая приведена ниже. Это невозможно со структурами.

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.

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

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

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

общая память, которую он получает => 5 байт

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

общая память, которую он получает = 4 байта

Использование союза Союзы часто используются, когда требуются диалоги специализированного типа. Чтобы получить представление о пользе союза. Стандартная библиотека 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 человека, они могут сидеть в кресле их размера соответственно.

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

Технически говоря означает:

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

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

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

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

Отличное объяснение. Ваше здоровье!

Prem 21.08.2017 11:41

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

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

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

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

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

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

Таким образом, для структуры 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/

Другие вопросы по теме