2008-12-06 4 views
336

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

ответ

568

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

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

редактировать: Если вам интересно, что установка x.b для «с» изменяет значение x.a к технически говоря, это не определено. На большинстве современных машин в полукокс 1 байт и ИНТ 4 байта, поэтому дает хЪ значение «с» также дает первый байт ха то же самое значение:

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

отпечатки

99, 99 

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

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); 

отпечатки

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

НО

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

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

+6

спасибо, это дает очень четкий и хороший ответ. хороший пример, чтобы пройти ... – gagneet 2008-12-06 18:14:39

+0

, используя этот пример, в союзе, если x.b = 'c', что хранится в x.a? это ссылочный номер символа? – kylex 2008-12-06 19:04:40

+0

надеюсь, что более подробно объясняется, что хранится в x.a, когда вы устанавливаете x.b. – 2008-12-06 19:33:52

9

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

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

+2

Вы можете также добавить что члены профсоюза «накладываются» друг на друга тем, что все они начинаются с самого начала адреса распределенной объединенной «структуры». – 2008-12-06 18:01:50

11

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

37

Как вы уже указать в вашем вопросе, главное различие между union и struct является то, что union членов перекрывают память друг друга, так что SizeOf профсоюза является один, в то время как 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* или bool*. Если вы указали адрес test на номер int*, он будет указывать на его первый член, a, на самом деле. То же самое верно и для союза. Таким образом, так как объединение всегда будет иметь правильное выравнивание, вы можете использовать союз, чтобы указывать на некоторый тип уважительной:

union a { 
    int a; 
    double b; 
}; 

Этот союз будет на самом деле быть в состоянии указать на межд, а двойной:

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

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

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

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

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

9

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

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

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

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

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

40

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

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

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

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

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

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

11

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

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

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

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

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

16

A 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; 
} 

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


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

Cheers!

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

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

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

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

общий объем памяти, это получить => 5 байт

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

общий объем памяти он получит = 4 байта

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() я вызывается с коротким целым числом, это было possble использовать putc() и FWRITE(). Но я хотел бы показать пример, чтобы dominstrate как союз может быть использован

11

Non технически говоря средства:

Успенских: стул = блок памяти, люди = переменная

Структура: Если есть 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 бит).

1

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

1

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

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

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

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

Здесь есть два члена внутри структуры и накидной: междунар и долгое междунар. Объем памяти для 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; 
} 

Ref: http://www.codingpractise.com/home/c-programming/structure-and-union/

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