Wcześniej korzystałem ze związków zawodowych; dzisiaj byłem zaniepokojony, gdy przeczytałem ten post i dowiedziałem się, że ten kod
union ARGB
{
uint32_t colour;
struct componentsTag
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} components;
} pixel;
pixel.colour = 0xff040201; // ARGB::colour is the active member from now on
// somewhere down the line, without any edit to pixel
if(pixel.components.a) // accessing the non-active member ARGB::components
jest w rzeczywistości nieokreślonym zachowaniem, to znaczy czytanie od członka związku innego niż ten, do którego ostatnio napisano, prowadzi do nieokreślonego zachowania. Jeśli nie jest to zamierzone użycie związków, co to jest? Czy ktoś może wyjaśnić to szczegółowo?
Aktualizacja:
Chciałem wyjaśnić kilka rzeczy z perspektywy czasu.
- Odpowiedź na pytanie nie jest taka sama dla C i C ++; moje nieświadome młodsze ja oznaczyło to jako C i C ++.
- Po przejrzeniu standardu C ++ 11 nie mogłem definitywnie stwierdzić, że wywołuje on dostęp / inspekcję nieaktywnego członka związku jest niezdefiniowany / nieokreślony / zdefiniowany w implementacji. Wszystko, co mogłem znaleźć, to §9.5 / 1:
Jeśli unia układu standardowego zawiera kilka struktur o układzie standardowym, które mają wspólną sekwencję początkową i jeśli obiekt tego typu ułożenia standardowego układu zawiera jedną ze struktur układu standardowego, dozwolone jest sprawdzenie wspólnej sekwencji początkowej dowolnej elementów struktury o standardowym układzie. § 9.2 / 19: Dwie struktury o standardowym układzie mają wspólną sekwencję początkową, jeśli odpowiadające elementy mają typy zgodne z układem i żaden z nich nie jest polem bitowym lub oba są polami bitowymi o tej samej szerokości dla sekwencji jednego lub więcej początkowych członkowie.
- Będąc w C, ( C99 TC3 - DR 283 i nowsze) jest to legalne ( podziękowania dla Pascala Cuoqa za podniesienie tego). Jednak próba zrobienia tego może nadal prowadzić do nieokreślonego zachowania , jeśli odczytana wartość okazuje się być niepoprawna (tak zwana „reprezentacja pułapki”) dla typu, przez który jest czytana. W przeciwnym razie odczytana wartość jest zdefiniowana jako implementacja.
C89 / 90 wywołało to w nieokreślonym zachowaniu (załącznik J), a książka K&R mówi, że jego implementacja jest zdefiniowana. Cytat z K&R:
Taki jest cel unii - pojedynczej zmiennej, która może zgodnie z prawem posiadać dowolny z kilku typów. [...] tak długo, jak użytkowanie jest spójne: pobrany typ musi być typem ostatnio zapisanym. Obowiązkiem programisty jest śledzenie, który typ jest obecnie przechowywany w związku; wyniki zależą od implementacji, jeśli coś jest przechowywane jako jeden typ i wyodrębniane jako inny.
Wyciąg z TC ++ PL Stroustrupa (moje wyróżnienie)
Użycie związków może być kluczowe dla zgodności danych [...] czasami niewłaściwie wykorzystywanych do „konwersji typu ”.
Przede wszystkim to pytanie (którego tytuł pozostaje niezmieniony od mojego pytania) zostało postawione z zamiarem zrozumienia celu związków ORAZ nie na temat tego, co pozwala standard. Np. Używanie dziedziczenia do ponownego użycia kodu jest oczywiście dozwolone przez standard C ++, ale nie było to celem ani pierwotną intencją wprowadzenia dziedziczenia jako funkcji języka C ++ . To jest powód, dla którego odpowiedź Andreya pozostaje nadal akceptowana.
scouring C++11's standard I couldn't conclusively say that it calls out accessing/inspecting a non-active union member is undefined [...] All I could find was §9.5/1
...naprawdę? cytujesz notatkę o wyjątku , a nie główny punkt na początku akapitu : „W związku, co najwyżej jeden z niestatycznych elementów danych może być aktywny w dowolnym momencie, to znaczy wartość co najwyżej jednego z elementy danych niestatycznych mogą być przechowywane w unii w dowolnym momencie. ” - i do p4: „Ogólnie rzecz biorąc, należy użyć jawnych wywołań destruktora i umieszczać nowych operatorów, aby zmienić aktywnego członka związku ”
b, g, r,
ia
może nie być ciągły, a tym samym nie pasować do układu auint32_t
. Jest to dodatek do problemów Endianess, na które zwracali uwagę inni.