C Language
fackföreningar
Sök…
Skillnad mellan struktur och förening
Detta illustrerar att fackliga medlemmar delar minne och att struktmedlemmar inte delar minne.
#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;
}
Använda fackföreningar för att tolka värden på nytt
Vissa C-implementeringar tillåter kod att skriva till en medlem av en fackföreningstyp och läser sedan från en annan för att utföra en sorts tolkning på nytt (analysera den nya typen som bitrepresentation av den gamla).
Det är dock viktigt att notera, detta är inte tillåtet av C-standardströmmen eller tidigare och kommer att resultera i odefinierat beteende, men inte desto mindre är ett mycket vanligt tillägg som erbjuds av kompilatorer (så kontrollera dina kompilatordokument om du planerar att göra detta) .
Ett verkligt exempel på denna teknik är algoritmen "Fast Inverse Square Root" som förlitar sig på implementeringsdetaljer för IEEE 754-flytpunktsnummer för att utföra en invers kvadratrot snabbare än med flytande punktoperationer. Denna algoritm kan utföras antingen genom pekargjutning (vilket är mycket farligt och bryter den strikta aliasregeln) eller genom en fackförening (som fortfarande är odefinierat beteende men fungerar i många kompilatorer):
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);
}
Denna teknik användes ofta i datorgrafik och spel tidigare, på grund av dess högre hastighet jämfört med att använda flytande punktoperationer, och är mycket en kompromiss, förlorar viss noggrannhet och är mycket icke bärbar i utbyte mot hastighet.
Skriva till en facklig medlem och läsa från en annan
Medlemmarna i en fackförening delar samma utrymme i minnet. Detta innebär att skrivning till en medlem skriver över data i alla andra medlemmar och att läsning från en medlem resulterar i samma data som läsning från alla andra medlemmar. Eftersom fackföreningsmedlemmar kan ha olika typer och storlekar kan data som läses dock tolkas annorlunda, se http://www.riptutorial.com/c/example/9399/using-unions-to-reinterpret-values
Det enkla exemplet nedan visar en förening med två medlemmar, båda av samma typ. Det visar att skrivande till medlem m_1
resulterar i att det skrivna värdet läses från medlem m_2
och att skriva till medlem m_2
resulterar i att det skrivna värdet läses från medlem 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;
}
Resultat
u.m_2: 1
u.m_1: 2