Różnica między strukturą a Unią

Czy Jest jakiś dobry przykład, aby dać różnicę między struct a union? Zasadniczo wiem, że struct używa całej pamięci swojego członka i union używa największej przestrzeni pamięci członków. Czy jest jakaś inna różnica poziomów systemu operacyjnego?

Author: Paolo Forgia, 2008-12-06

15 answers

Z Unią, powinieneś używać tylko jednego z elementów, ponieważ wszystkie są przechowywane w tym samym miejscu. To sprawia, że jest to przydatne, gdy chcesz przechowywać coś, co może być jednym z kilku typów. Z drugiej strony struktura ma oddzielne miejsce pamięci dla każdego ze swoich elementów i wszystkie mogą być używane jednocześnie.

Aby podać konkretny przykład ich użycia, pracowałem nad interpreterem Scheme jakiś czas temu i zasadniczo nakładałem typy danych Scheme na C typy danych. Wymagało to przechowywania w strukturze enum wskazującego typ wartości i Unii do przechowywania tej wartości.

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: Jeśli zastanawiasz się, jakie ustawienie x.B na 'c' zmienia wartość x.a na, technicznie rzecz biorąc, jest niezdefiniowana. Na większości nowoczesnych maszyn znak ma 1 bajt, A int 4 bajty, więc podając x. B wartość " c " daje również pierwszy bajt x. A tę samą wartość:

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

Druki

99, 99

Dlaczego te dwie wartości są takie same? Bo Ostatnie 3 bajty int 3 są równe zeru, więc odczytuje się je również jako 99. Jeśli umieścimy większą liczbę dla x. a, zobaczysz, że nie zawsze tak jest:

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

Druki

387427, 99

Aby przyjrzeć się bliżej rzeczywistym wartościom pamięci, ustawmy i wydruk wartości w hex:

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

Druki

deadbe22, 22

Widać wyraźnie, gdzie 0x22 nadpisuje 0xEF.

Ale

W C, kolejność bajtów w int jest nie zdefiniowana. Ten program overwrote 0xEF z 0x22 na moim Macu, ale są inne platformy, gdzie byłoby zastąpić 0xDE zamiast ponieważ kolejność bajtów, które tworzą int zostały odwrócone. Dlatego pisząc program, nigdy nie należy polegać na zachowaniu nadpisywania określonych danych w związku, ponieważ nie jest on przenośny.

Aby dowiedzieć się więcej o kolejności bajtów, sprawdź endianness.

 704
Author: Kyle Cronin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-27 14:34:00

Oto krótka odpowiedź: struktura jest strukturą rekordową: każdy element struktury przydziela nową przestrzeń. Tak więc struktura jak

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

Przydziela co najmniej (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) bajty w pamięci dla każdej instancji. ("Co najmniej", ponieważ ograniczenia wyrównania architektury mogą wymusić na kompilatorze blokowanie struktury.)

Z drugiej strony,

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

Przydziela jeden kawałek pamięci i nadaje mu cztery aliasy. Więc sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)), znowu z możliwością dodawania dla wyrównań.

 85
Author: Charlie Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-06 18:32:00

Czy Jest jakiś dobry przykład, aby dać różnicę między 'strukturą' a 'Unią'?

Wymyślony protokół komunikacyjny

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

W tym wyimaginowanym protokole określono, że na podstawie "typu wiadomości" następująca lokalizacja w nagłówku będzie albo numerem żądania, albo czteroznakowym kodem, ale nie obydwoma. Krótko mówiąc, związki pozwalają tej samej lokalizacji przechowywania reprezentować więcej niż jeden typ danych, gdzie masz gwarancję, że będziesz chcesz przechowywać tylko jeden z typów danych w tym samym czasie.

Związki są w dużej mierze niskopoziomowym szczegółem opartym na dziedzictwie C jako systemowego języka programowania, gdzie czasami używane są w ten sposób" nakładające się " miejsca przechowywania. Czasami możesz użyć związków do zapisywania pamięci, w której masz strukturę danych, w której jednocześnie zostanie zapisany tylko jeden z kilku typów.

Ogólnie rzecz biorąc, system operacyjny nie dba ani nie wie o strukturach i związkach-oba są po prostu blokami pamięci. Struktura jest blokiem pamięci, który przechowuje kilka obiektów danych, gdzie obiekty te nie nakładają się na siebie. Unia jest blokiem pamięci, który przechowuje kilka obiektów danych, ale przechowuje tylko największy z nich, a zatem może przechowywać tylko jeden z obiektów danych w tym samym czasie.

 57
Author: cygil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-04 12:30:51

Jak już pan stwierdził w swoim pytaniu, główną różnicą między union i struct jest to , że członkowie union nakładają się na siebie nawzajem tak, że rozmiar związku jest jeden, podczas gdy członkowie struct są ułożeni jeden po drugim (z opcjonalnym wypełnieniem pomiędzy). Również związek jest wystarczająco duży, aby pomieścić wszystkich swoich członków i mieć wyrównanie, które pasuje do wszystkich jego członków. Powiedzmy więc, że int może być przechowywana tylko pod 2-bajtowymi adresami i ma szerokość 2 bajtów, A long może być przechowywany tylko pod 4 adresów bajtowych i ma długość 4 bajtów. Następująca Unia

union test {
    int a;
    long b;
}; 

Może mieć sizeof 4, a wymóg wyrównania 4. Zarówno Unia, jak i struktura mogą mieć wyściółkę na końcu, ale nie na początku. Zapis do struktury zmienia tylko wartość elementu, do którego jest zapisany. Pisanie do członka Związku spowoduje unieważnienie wartości wszystkich innych członków. Nie możesz uzyskać do nich dostępu, jeśli nie napisałeś do nich wcześniej, w przeciwnym razie zachowanie jest niezdefiniowane. GCC zapewnia jako rozszerzenie, które możesz przeczytać od członków związku, nawet jeśli nie napisałeś do nich ostatnio. W przypadku systemu operacyjnego nie ma znaczenia, czy program użytkownika pisze do Unii, czy do struktury. W rzeczywistości jest to tylko kwestia kompilatora.

Kolejną ważną właściwością union i struct jest to, że pozwalają one wskazywać na typy dowolnych jej członków. Zatem obowiązuje:

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

Some_test_pointer może wskazywać na int* lub double*. Jeśli rzucisz adres typu test na int*, wskaże on pierwszy człon a. To samo dotyczy również Unii. Tak więc, ponieważ Unia zawsze będzie miała odpowiednie wyrównanie, możesz użyć Unii, aby wskazywanie na jakiś typ było ważne: {]}

union a {
    int a;
    double b;
};

Ta Unia będzie w stanie wskazać na int i podwójne:

union a * v = (union a*)some_int_pointer;
*some_int_pointer = 5;
v->a = 10;
return *some_int_pointer;    
W rzeczywistości jest to poprawne, zgodnie ze standardem C99:

Obiekt powinien mieć swój zapis wartość dostępna tylko przez wyrażenie lvalue, które ma jeden z następujących typów:

  • Typ zgodny z efektywnym typem obiektu
  • ...
  • Typ zbiorczy lub union, który obejmuje jeden z wyżej wymienionych typów wśród swoich członków

Kompilator nie zoptymalizuje v->a = 10;, ponieważ może to wpłynąć na wartość *some_int_pointer (a funkcja zwróci 10 zamiast 5).

 39
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-16 13:29:42

A union jest przydatny w kilku scenariuszach. union może być narzędziem do manipulacji na bardzo niskim poziomie, takim jak pisanie sterowników urządzeń dla jądra.

Przykładem tego jest rozdzielenie float liczby za pomocą union z struct z bitfieldami i float. Zapisuję numer w float, a później mogę uzyskać dostęp do poszczególnych części float Poprzez struct. Przykład pokazuje, jak union jest używany, aby mieć różne kąty patrzenia na dane.

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

Spójrz na single precision opis na Wikipedii. Użyłem przykładu i magicznej liczby 0.15625 stamtąd.


union może być również używany do implementacji algebraicznego typu danych, który ma wiele alternatyw. Znalazłem tego przykład w książce "Real World Haskell" autorstwa O ' Sullivana, Stewarta i Goerzena. Sprawdź to w sekcji The discriminated union .

Zdrówko!
 18
Author: Krzysztof Voss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 17:24:56

"union " i " struct " są } konstrukcjami języka C. Mówienie o różnicy" poziomu systemu operacyjnego " między nimi jest niewłaściwe, ponieważ to kompilator tworzy inny kod, jeśli używasz jednego lub innego słowa kluczowego.

 11
Author: Gabriele D'Antona,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-06 18:06:13

Masz to, to wszystko. Ale po co związki?

Możesz umieścić w tej samej lokalizacji zawartość różnych typów. Musisz znać Typ tego, co przechowujesz w Unii (tak często umieszczasz to w struct z tagiem type...).

Dlaczego to jest ważne? Nie do końca dla zysków z kosmosu. Tak, możesz zdobyć kilka bitów lub zrobić wyściółkę, ale to już nie jest główny punkt.

To dla bezpieczeństwa typu, pozwala na wykonanie jakiegoś "dynamiczne pisanie": kompilator wie, że treść może mieć różne znaczenia, a dokładne znaczenie sposobu interpretacji zależy od Ciebie w czasie wykonywania. Jeśli masz wskaźnik, który może wskazywać na różne typy, musisz użyć Unii, w przeciwnym razie kod może być nieprawidłowy z powodu problemów z aliasingiem (kompilator mówi do siebie: "och, tylko ten wskaźnik może wskazywać na ten typ, więc mogę zoptymalizować te dostępy...", a złe rzeczy mogą się zdarzyć).

 11
Author: Piotr Lesnicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-06 18:30:27

Nie mówiąc technicznie oznacza:

Założenie: krzesło = blok pamięci, ludzie = zmienna

Struktura : Jeśli są 3 osoby, mogą usiąść w fotelu o odpowiedniej wielkości .

Union: Jeśli są 3 osoby tylko jedno krzesło będzie tam siedzieć, wszyscy muszą używać tego samego krzesła, gdy chcą usiąść .

Technicznie rzecz biorąc oznacza:

Poniższy program daje głębokie zanurzenie w strukturze i Unii razem .

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) for bufferaddr + sizeof(UNIT32) for union + 32 bit dla padding(zależy od architektury procesora) = 128 bitów . Dla struktury wszyscy członkowie otrzymują blok pamięci sąsiadująco .

Union otrzymuje jeden blok pamięci o maksymalnym rozmiarze członka(tutaj jego 32-bitowy). Wewnątrz Unii leży jeszcze jedna struktura (INNER_STRUCT) jej członkowie otrzymują blok pamięci o łącznej wielkości 32 bitów(16+8+8). W Unii albo inner_struct (32 bit) członek Można uzyskać dostęp do danych(32-bitowych).

 11
Author: skanda93,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 06:04:56

Tak, główna różnica między struct i union jest taka sama, jak powiedziałeś. Struct wykorzystuje całą pamięć swoich członków, a union wykorzystuje największą przestrzeń pamięci członków.

Ale cała różnica polega na potrzebie użycia pamięci. Najlepsze wykorzystanie Unii można zobaczyć w procesach Uniksa, gdzie używamy sygnałów. tak jak proces może działać tylko na jednym sygnale na raz. Więc ogólna deklaracja będzie brzmiała:

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

W tym przypadku proces wykorzystuje tylko najwyższe pamięć wszystkich sygnałów. ale jeśli w tym przypadku użyjesz struct, użycie pamięci będzie sumą wszystkich sygnałów. To wielka różnica.

Podsumowując, Unia powinna być wybrana, jeśli wiesz, że masz dostęp do jednego z członków na raz.

 11
Author: Ravi Kanth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-19 19:07:36

Struktura przydziela Całkowity rozmiar wszystkich elementów w niej.

Związek przydziela tylko tyle pamięci, ile wymaga jego największy członek.

 10
Author: Christian C. Salvadó,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-06 17:58:56

Jaka jest różnica między strukturą a Unią?

Krótka odpowiedź brzmi: szacunek jest w alokacji pamięci. Wyjaśnienie: W strukturze zostanie utworzona przestrzeń pamięci dla wszystkich członków wewnątrz struktury. W Unii przestrzeń pamięci będzie tworzona tylko dla członka, który potrzebuje największej przestrzeni pamięci. Rozważmy następujący kod:

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

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

Wewnątrz struct i union jest dwóch członków: int i long int. Przestrzeń pamięci dla int wynosi: 4 bajty, a przestrzeń pamięci dla long int wynosi: 8 w 32-bitowy system operacyjny.

Więc dla struct 4+8=12 bajtów zostanie utworzonych, podczas gdy 8 bajtów zostanie utworzonych dla union

Przykład kodu:

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

 4
Author: Abdus Sattar Bhuiyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-04 07:26:30

Zastosowania Unii Związki są często używane, gdy potrzebne są specjalistyczne rozmowy typu. Aby zrozumieć przydatność Unii. Biblioteka standardowa c / c nie definiuje żadnej funkcji specjalnie zaprojektowanej do zapisu krótkich liczb całkowitych do pliku. Użycie fwrite() powoduje nadmierne obciążenie dla prostej obsługi. Jednak za pomocą Unii można łatwo utworzyć funkcję, która zapisuje binarną krótką liczbę całkowitą do pliku jeden bajt na raz. Zakładam, że krótkie liczby całkowite są 2 bajtowe long

PRZYKŁAD:

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

Chociaż wywołałem putw() z krótką liczbą całkowitą, możliwe było użycie putc () i fwrite (). Ale chciałem pokazać przykład, aby dominstrated jak Unia może być używany

 3
Author: Ahmed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-13 10:12:07

Struktura to zbiór różnych typów danych, w których mogą się znajdować różne typy danych i każdy dostaje swój własny blok pamięci

Zwykle używamy union, gdy mamy pewność, że tylko jedna zmienna będzie używana na raz i chcemy w pełni wykorzystać obecną pamięć, ponieważ otrzymuje ona tylko jeden blok pamięci, który jest równy największemu typowi.

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

Total memory it get = > 5 bajtów

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

Total memory it get = 4 byte

 3
Author: Anurag Bhakuni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-18 03:54:13

Związki przydają się podczas pisania funkcji porządkowania bajtów, która jest podana poniżej. To niemożliwe ze strukturami.

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.
 2
Author: Aniket Suryavanshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-04 19:41:21

Unia różni się od struktury, ponieważ Unia powtarza się nad innymi: redefiniuje tę samą pamięć, podczas gdy struktura definiuje jedną po drugiej bez nakładania się lub redefinicji.

 1
Author: Dennis Ng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-04 15:03:42