C Language
sindacati
Ricerca…
Differenza tra struttura e unione
Questo dimostra che i membri del sindacato condividono la memoria e che i membri della struttura non condividono la memoria.
#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;
}
Utilizzare i sindacati per reinterpretare i valori
Alcune implementazioni C consentono al codice di scrivere su un membro di un tipo di unione e poi a leggerlo da un altro per eseguire una sorta di cast di reinterpretazione (analizzando il nuovo tipo come rappresentazione bit di quello vecchio).
È importante notare, tuttavia, che questo non è consentito dallo standard C corrente o passato e risulterà in un comportamento indefinito, tuttavia è un'estensione molto comune offerta dai compilatori (quindi controllare i documenti del compilatore se si prevede di farlo) .
Un vero esempio di questa tecnica è l'algoritmo "Fast Inverse Square Root" che si basa sui dettagli di implementazione dei numeri in virgola mobile IEEE 754 per eseguire una radice quadrata inversa più rapidamente rispetto all'utilizzo di operazioni in virgola mobile, questo algoritmo può essere eseguito tramite puntatore (che è molto pericoloso e infrange la rigida regola dell'aliasing) o attraverso un'unione (che è ancora un comportamento indefinito ma funziona in molti compilatori):
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);
}
Questa tecnica è stata ampiamente utilizzata in computer grafica e giochi in passato a causa della sua maggiore velocità rispetto all'utilizzo di operazioni in virgola mobile, ed è molto compromessa, perdendo un po 'di precisione ed essendo molto non portatile in cambio di velocità.
Scrivendo a un membro del sindacato e leggendo da un altro
I membri di un'unione condividono lo stesso spazio in memoria. Ciò significa che la scrittura su un membro sovrascrive i dati in tutti gli altri membri e che la lettura da un membro produce gli stessi dati letti da tutti gli altri membri. Tuttavia, poiché i membri del sindacato possono avere tipi e dimensioni differenti, i dati letti possono essere interpretati in modo diverso, vedi http://www.Scriptutorial.com/c/example/9399/using-unions-to-reinterpret-values
Il semplice esempio qui sotto dimostra un'unione con due membri, entrambi dello stesso tipo. Mostra che scrivendo al membro m_1
il valore scritto viene letto dal membro m_2
e la scrittura nel membro m_2
comporta la lettura del valore scritto dal membro 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;
}
Risultato
u.m_2: 1
u.m_1: 2