Szukaj…


Różnica między struct a union

To pokazuje, że członkowie związku dzielą pamięć, a członkowie struktury nie dzielą pamięci.

#include <stdio.h>
#include <string.h>

union My_Union
{
  int variable_1;
  int variable_2;
};

struct My_Struct
{
  int variable_1;
  int variable_2;
};

int main (void)
{
  union My_Union u;
  struct My_Struct s;
  u.variable_1 = 1;
  u.variable_2 = 2;
  s.variable_1 = 1;
  s.variable_2 = 2;
  printf ("u.variable_1: %i\n", u.variable_1);
  printf ("u.variable_2: %i\n", u.variable_2);
  printf ("s.variable_1: %i\n", s.variable_1);
  printf ("s.variable_2: %i\n", s.variable_2);
  printf ("sizeof (union My_Union): %i\n", sizeof (union My_Union));
  printf ("sizeof (struct My_Struct): %i\n", sizeof (struct My_Struct));
  return 0;
}

Używanie związków do reinterpretacji wartości

Niektóre implementacje języka C pozwalają na zapis kodu do jednego elementu typu unii, a następnie odczytanie go w innym celu wykonania pewnego rodzaju rzutowania reinterpretacyjnego (parsowanie nowego typu jako reprezentacji bitowej starego).

Należy jednak pamiętać, że nie jest to dozwolone w obecnym lub przeszłym standardzie C i spowoduje niezdefiniowane zachowanie, jednak jest to bardzo popularne rozszerzenie oferowane przez kompilatory (więc sprawdź dokumentację kompilatora, jeśli planujesz to zrobić) .

Jednym z prawdziwych przykładów tej techniki jest algorytm „szybkiego odwrotnego pierwiastka kwadratowego”, który opiera się na szczegółach implementacji liczb zmiennoprzecinkowych IEEE 754 w celu wykonania odwrotnego pierwiastka kwadratowego szybciej niż przy użyciu operacji zmiennoprzecinkowych, algorytm ten można wykonać albo za pomocą rzutowania wskaźnika (co jest bardzo niebezpieczne i łamie ścisłą zasadę aliasingu) lub poprzez połączenie (które jest nadal niezdefiniowanym zachowaniem, ale działa w wielu kompilatorach):

union floatToInt
{
    int32_t intMember;
    float floatMember; /* Float must be 32 bits IEEE 754 for this to work */
};

float inverseSquareRoot(float input)
{
    union floatToInt x;
    int32_t i;
    float f;
    x.floatMember = input;     /* Assign to the float member */
    i = x.intMember;           /* Read back from the integer member */
    i = 0x5f3759df - (i >> 1);
    x.intMember = i;           /* Assign to the integer member */
    f = x.floatMember;         /* Read back from the float member */
    f = f * (1.5f - input * 0.5f * f * f);
    return f * (1.5f - input * 0.5f * f * f);
}

Technika ta była w przeszłości szeroko stosowana w grafice komputerowej i grach ze względu na jej większą prędkość w porównaniu do operacji zmiennoprzecinkowych, i stanowi bardzo duży kompromis, tracąc pewną dokładność i będąc bardzo nieprzenośnym w zamian za szybkość.

Pisanie do jednego członka związku i czytanie od innego

Członkowie związku dzielą tę samą przestrzeń w pamięci. Oznacza to, że zapis do jednego członka powoduje nadpisanie danych we wszystkich innych elementach, a odczyt z jednego elementu daje te same dane, co odczyt z wszystkich innych elementów. Ponieważ jednak członkowie związku mogą mieć różne typy i rozmiary, odczytywane dane mogą być interpretowane w różny sposób, patrz http://www.riptutorial.com/c/example/9399/using-unions-to-reinterpret-values

Prosty przykład poniżej pokazuje związek z dwoma członkami tego samego typu. Pokazuje, że zapis do elementu m_1 powoduje odczytanie zapisanej wartości z elementu m_2 a zapis do elementu m_2 powoduje odczytanie zapisanej wartości z elementu m_1 .

#include <stdio.h>

union my_union /* Define union */
{
    int m_1;
    int m_2;
};

int main (void)
{
    union my_union u;             /* Declare union */
    u.m_1 = 1;                    /* Write to m_1 */
    printf("u.m_2: %i\n", u.m_2); /* Read from m_2 */
    u.m_2 = 2;                    /* Write to m_2 */
    printf("u.m_1: %i\n", u.m_1); /* Read from m_1 */
    return 0;
}

Wynik

u.m_2: 1
u.m_1: 2


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow