W związku musisz użyć tylko jednego z elementów, ponieważ wszystkie są przechowywane w tym samym miejscu. Jest to przydatne, gdy chcesz przechowywać coś, co może być jednym z kilku typów. Z drugiej strony, struct ma osobne miejsce w pamięci dla każdego z jego elementów i można z nich korzystać jednocześnie.
Aby podać konkretny przykład ich zastosowania, jakiś czas temu pracowałem nad interpretatorem schematu i zasadniczo nakładałem typy danych schematu na typy danych C. Polegało to na przechowywaniu w strukturze wyliczenia 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
edycja: Jeśli zastanawiasz się, jakie ustawienie xb na „c” zmienia wartość xa na, technicznie rzecz biorąc jest niezdefiniowana. Na większości nowoczesnych maszyn char ma 1 bajt, a int 4 bajty, więc podanie xb wartości „c” daje również pierwszemu bajtowi xa tę samą wartość:
union foo x;
x.a = 3;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);
odciski
99, 99
Dlaczego dwie wartości są takie same? Ponieważ wszystkie 3 ostatnie bajty liczby całkowitej 3 są równe zero, więc jest również czytane jako 99. Jeśli wstawimy większą liczbę dla xa, zobaczysz, że nie zawsze tak jest:
union foo x;
x.a = 387439;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);
odciski
387427, 99
Aby przyjrzeć się bliżej faktycznym wartościom pamięci, ustawmy i wydrukujmy wartości szesnastkowe:
union foo x;
x.a = 0xDEADBEEF;
x.b = 0x22;
printf("%x, %x\n", x.a, x.b);
odciski
deadbe22, 22
Możesz wyraźnie zobaczyć, gdzie 0x22 nadpisał 0xEF.
ALE
W C kolejność bajtów w int nie jest zdefiniowana. Ten program nadpisał 0xEF wartością 0x22 na moim komputerze Mac, ale istnieją inne platformy, na których zastąpiłby 0xDE, ponieważ kolejność bajtów tworzących liczbę całkowitą została odwrócona. Dlatego pisząc program, nigdy nie powinieneś polegać na zachowaniu nadpisywania określonych danych w związku, ponieważ nie jest ono przenośne.
Aby uzyskać więcej informacji na temat porządkowania bajtów, sprawdź endianness .
Oto krótka odpowiedź: struct jest strukturą rekordową: każdy element w strukturze przydziela nową przestrzeń. Więc taka struktura
przydziela co najmniej
(sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double))
bajty w pamięci dla każdej instancji. („Przynajmniej”, ponieważ ograniczenia wyrównania architektury mogą zmusić kompilator do wypełnienia struktury).Z drugiej strony,
przydziela jeden fragment pamięci i daje mu cztery aliasy. Tak więc
sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double))
znowu z możliwością pewnego dodania do wyrównania.źródło
Urojony protokół komunikacyjny
W tym wyimaginowanym protokole określono, że w oparciu o „typ wiadomości” następująca lokalizacja w nagłówku będzie albo numerem żądania, albo czteroznakowym kodem, ale nie jednym i drugim. Krótko mówiąc, związki pozwalają, aby ta sama lokalizacja pamięci reprezentowała więcej niż jeden typ danych, przy czym gwarantuje się, że będziesz chciał przechowywać tylko jeden typ danych w danym momencie.
Związki są w dużej mierze szczegółami niskiego poziomu, opartymi na dziedzictwie C jako systemowego języka programowania, w którym czasami wykorzystuje się „nakładające się” miejsca przechowywania. Czasami możesz użyć związków, aby zaoszczędzić pamięć tam, gdzie masz strukturę danych, w której tylko jeden z kilku typów zostanie zapisany jednocześnie.
Ogólnie rzecz biorąc, system operacyjny nie dba o struktury i związki i nie wie o nich - są to po prostu bloki pamięci. Struktura to blok pamięci, który przechowuje kilka obiektów danych, przy czym obiekty te nie nakładają się. Unia to blok pamięci, który przechowuje kilka obiektów danych, ale ma tylko pamięć dla największego z nich, a zatem może przechowywać tylko jeden obiekt danych w tym samym czasie.
źródło
packetheader ph;
jak uzyskać dostęp do numeru żądania?ph.request.requestnumber
?Jak już wspomniałeś w swoim pytaniu, główna różnica między
union
istruct
polega na tym, żeunion
członkowie nakładają się na siebie nawzajem, tak że rozmiar związku jest tym samym, podczas gdystruct
członkowie są układani jeden po drugim (z opcjonalnym wypełnieniem pomiędzy nimi). Również związek jest wystarczająco duży, aby pomieścić wszystkich jego członków, i mieć wyrównanie, które pasuje do wszystkich jego członków. Powiedzmy, żeint
może być przechowywany tylko pod 2-bajtowymi adresami i ma szerokość 2 bajtów, a długi może być przechowywany tylko pod 4-bajtowymi adresami i ma 4 bajty długości. Następujący związekmoże mieć wartość
sizeof
4, a wymaganie wyrównania wynosi 4. Zarówno związek, jak i struktura mogą mieć wypełnienie na końcu, ale nie na początku. Zapis do struktury zmienia tylko wartość członka zapisanego do. Zapis do członka związku spowoduje utratę wartości wszystkich pozostałych członków. Nie możesz uzyskać do nich dostępu, jeśli wcześniej do nich nie napisałeś, w przeciwnym razie zachowanie jest niezdefiniowane. GCC zapewnia jako rozszerzenie, które możesz odczytać od członków związku, nawet jeśli nie napisałeś do nich ostatnio. W przypadku systemu operacyjnego nie musi mieć znaczenia, czy program użytkownika zapisuje do unii, czy do struktury. To właściwie tylko kwestia kompilatora.Inną ważną właściwością union i struct jest to, że pozwalają one, aby wskaźnik do nich wskazywał typy dowolnego z jego członków . Dlatego obowiązują następujące zasady:
some_test_pointer może wskazywać na
int*
lubdouble*
. Jeśli rzucisz adres typutest
naint*
, będzie on wskazywał na jego pierwszego członkaa
. To samo dotyczy związku. Tak więc, ponieważ związek zawsze będzie miał prawidłowe wyrównanie, możesz użyć związku, aby wskazać jakiś typ:Ten związek faktycznie będzie w stanie wskazać int i podwójne:
jest faktycznie ważny, jak stwierdzono w standardzie C99:
Kompilator nie zoptymalizuje,
v->a = 10;
ponieważ może to wpłynąć na wartość*some_int_pointer
(a funkcja zwróci10
zamiast5
).źródło
union
Jest przydatna w kilka scenariuszy.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 rozcięcie
float
liczby za pomocąunion
polastruct
bitowego i pola afloat
. I zapisać numer wfloat
, a później mogę uzyskać dostęp do poszczególnych częścifloat
przez tostruct
. Przykład pokazuje, w jaki sposóbunion
używane są różne kąty patrzenia na dane.Spójrz na pojedynczy opis precyzji na wikipedii. Użyłem stamtąd przykładu i magicznej liczby 0.15625.
union
może także służyć do implementacji algebraicznego typu danych, który ma wiele alternatyw. Znalazłem przykład tego w książce O'Sullivana, Stewarta i Goerzena „Real World Haskell”. Sprawdź to w sekcji Związki dyskryminowane .Twoje zdrowie!
źródło
„ union ” i „ struct ” są konstrukcjami języka C. Mówienie o różnicy między nimi na poziomie systemu operacyjnego jest niewłaściwe, ponieważ to kompilator wytwarza inny kod, jeśli użyjesz jednego lub drugiego słowa kluczowego.
źródło
Mówiąc inaczej niż technicznie oznacza:
Założenie: krzesło = blok pamięci, ludzie = zmienna
Struktura : Jeśli są 3 osoby, mogą one odpowiednio siedzieć na krześle swojej wielkości.
Unia : Jeśli są 3 osoby, będzie tylko jedno krzesło, aby usiąść, wszyscy muszą korzystać z tego samego krzesła, kiedy chcą usiąść.
Technicznie rzecz biorąc oznacza:
Poniższy program daje głębokie zanurzenie w strukturze i jedności razem.
Całkowity rozmiar MAIN_STRUCT = sizeof (UINT64) dla bufferaddr + sizeof (UNIT32) dla unii + 32 bity dla padding (zależy od architektury procesora) = 128 bitów. Dla struktury wszyscy członkowie otrzymują blok pamięci w sposób ciągły.
Unia pobiera jeden blok pamięci elementu o maksymalnym rozmiarze (tutaj jego 32-bitowy). Wewnątrz unii leży jeszcze jedna struktura (INNER_STRUCT), jej członkowie otrzymują blok pamięci o całkowitej wielkości 32 bitów (16 + 8 + 8). W unii można uzyskać dostęp do elementu INNER_STRUCT (32 bity) lub danych (32 bity).
źródło
Tak, główna różnica między strukturą a związkiem jest taka sama, jak powiedziałeś. Struct wykorzystuje całą pamięć swojego członka, a związek używa największej przestrzeni pamięci członków.
Ale cała różnica polega na zużyciu pamięci. Najlepsze wykorzystanie unii można zaobserwować w procesach unixowych, w których wykorzystujemy sygnały. jak proces może działać tylko na jeden sygnał na raz. Tak więc ogólna deklaracja będzie:
W takim przypadku proces wykorzystuje tylko najwyższą pamięć ze wszystkich sygnałów. ale jeśli użyjesz struktury w tym przypadku, użycie pamięci będzie sumą wszystkich sygnałów. To robi dużą różnicę.
Podsumowując, Unia powinna zostać wybrana, jeśli wiesz, że masz dostęp do któregokolwiek z członków jednocześnie.
źródło
Masz, to wszystko. Ale w zasadzie jaki jest sens związków?
Możesz umieścić w tej samej lokalizacji różne typy. Musisz znać rodzaj tego, co przechowujesz w związku (tak często umieszczasz go w
struct
tagu typu ...).Dlaczego to jest ważne? Niezupełnie dla korzyści kosmicznych. Tak, możesz zyskać trochę bitów lub padding, ale to już nie jest główny punkt.
Jest to związane z bezpieczeństwem typu, umożliwia wykonywanie pewnego rodzaju „dynamicznego pisania”: kompilator wie, że treść może mieć różne znaczenia i dokładne znaczenie interpretacji 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ć niepoprawny 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ć z tych dostępów ... ”i mogą się zdarzyć złe rzeczy).
źródło
Struktura przydziela całkowity rozmiar wszystkich zawartych w niej elementów.
Związek przydziela tylko tyle pamięci, ile potrzebuje jego największy członek.
źródło
Jaka jest różnica między strukturą a zjednoczeniem?
Skrótowa odpowiedź brzmi: szacunek dotyczy alokacji pamięci. Objaśnienie: W strukturze przestrzeń pamięci zostanie utworzona dla wszystkich elementów wewnątrz struktury. W unii pamięć zostanie utworzona tylko dla członka, który potrzebuje największej przestrzeni pamięci. Rozważ następujący kod:
Oto dwóch członków wewnątrz struct i union: int i long int. Miejsce w pamięci dla int to: 4 bajty, a miejsce w pamięci dla long int wynosi: 8 w 32-bitowym systemie operacyjnym.
Więc dla struct 4 + 8 = 12 bajtów zostanie utworzonych, podczas gdy 8 bajtów zostanie utworzonych dla unii
Przykład kodu:
Patrz: http://www.codingpractise.com/home/c-programming/structure-and-union/
źródło
Zastosowania związków zawodowych są często używane, gdy potrzebne są specjalistyczne rozmowy typu. Aby dowiedzieć się o przydatności związku. Standardowa biblioteka c / c nie definiuje żadnej funkcji zaprojektowanej specjalnie do zapisywania krótkich liczb całkowitych w pliku. Użycie fwrite () powoduje nadmierne obciążenie dla prostej operacji. Jednak za pomocą unii można łatwo utworzyć funkcję, która zapisuje binarną krótką liczbę całkowitą do pliku po jednym bajcie. Zakładam, że krótkie liczby całkowite mają długość 2 bajtów
PRZYKŁAD:
chociaż putw () wywołałem z krótką liczbą całkowitą, można było użyć putc () i fwrite (). Chciałem jednak pokazać przykład, który zdominuje sposób użycia związku
źródło
Struktura to zbiór różnych typów danych, w których mogą znajdować się różne typy danych i każdy otrzymuje własny blok pamięci
zwykle używaliśmy unii, gdy jesteśmy pewni, że tylko jedna zmienna zostanie użyta jednocześnie i chcesz w pełni wykorzystać obecną pamięć, ponieważ otrzymuje ona tylko jeden blok pamięci, który jest równy największemu typowi.
całkowita pamięć to => 5 bajtów
całkowita pamięć to = 4 bajty
źródło
Związki przydają się podczas pisania funkcji porządkowania bajtów, która jest podana poniżej. Nie jest to możliwe w przypadku struktur.
źródło
Unia różni się od struktury, jak Unia powtarza się nad innymi: definiuje na nowo tę samą pamięć, podczas gdy struktura definiuje jedna po drugiej, bez nakładania się lub redefinicji.
źródło