Waarom hebben we C Unions nodig?

Wanneer moeten vakbonden worden gebruikt? Waarom hebben we ze nodig?


Antwoord 1, autoriteit 100%

Unionen worden vaak gebruikt om de binaire representaties van gehele getallen en floats om te zetten:

union
{
  int i;
  float f;
} u;
// Convert floating-point bits to integer:
u.f = 3.14159f;
printf("As integer: %08x\n", u.i);

Hoewel dit technisch ongedefinieerd gedrag is volgens de C-standaard (je mag alleen het veld lezen dat het meest recent is geschreven), zal het in vrijwel elke compiler op een goed gedefinieerde manier werken.

Verenigingen worden soms ook gebruikt om pseudo-polymorfisme in C te implementeren, door een structuur een tag te geven die aangeeft welk type object het bevat, en vervolgens de mogelijke typen samen te voegen:

enum Type { INTS, FLOATS, DOUBLE };
struct S
{
  Type s_type;
  union
  {
    int s_ints[2];
    float s_floats[2];
    double s_double;
  };
};
void do_something(struct S *s)
{
  switch(s->s_type)
  {
    case INTS:  // do something with s->s_ints
      break;
    case FLOATS:  // do something with s->s_floats
      break;
    case DOUBLE:  // do something with s->s_double
      break;
  }
}

Hierdoor kan de grootte van struct Sslechts 12 bytes zijn, in plaats van 28.


Antwoord 2, autoriteit 57%

Unions zijn met name handig bij Embedded-programmering of in situaties waar directe toegang tot de hardware/het geheugen nodig is. Hier is een triviaal voorbeeld:

typedef union
{
    struct {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
    } bytes;
    unsigned int dword;
} HW_Register;
HW_Register reg;

Dan heb je als volgt toegang tot het register:

reg.dword = 0x12345678;
reg.bytes.byte3 = 4;

Endianness (bytevolgorde) en processorarchitectuur zijn natuurlijk belangrijk.

Een andere handige functie is de bitmodifier:

typedef union
{
    struct {
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char reserved:4;
    } bits;
    unsigned char byte;
} HW_RegisterB;
HW_RegisterB reg;

Met deze code heb je direct toegang tot een enkele bit in het register/geheugenadres:

x = reg.bits.b2;

Antwoord 3, autoriteit 25%

Lage systeemprogrammering is een redelijk voorbeeld.

IIRC, ik heb vakbonden gebruikt om hardwareregisters op te splitsen in de componentbits. Je hebt dus toegang tot een 8-bits register (zoals het was, op de dag dat ik dit deed 😉 in de componentbits.

(Ik ben de exacte syntaxis vergeten, maar…) Deze structuur zou het mogelijk maken om toegang te krijgen tot een besturingsregister als een control_byte of via de individuele bits. Het zou belangrijk zijn om ervoor te zorgen dat de bits worden toegewezen aan de juiste registerbits voor een gegeven endianness.

typedef union {
    unsigned char control_byte;
    struct {
        unsigned int nibble  : 4;
        unsigned int nmi     : 1;
        unsigned int enabled : 1;
        unsigned int fired   : 1;
        unsigned int control : 1;
    };
} ControlRegister;

Antwoord 4, autoriteit 14%

Ik heb het in een aantal bibliotheken gezien als vervanging voor objectgeoriënteerde overerving.

Bijvoorbeeld

       Connection
     /       |       \
  Network   USB     VirtualConnection

Als je wilt dat de Connection “klasse” een van de bovenstaande is, kun je zoiets schrijven als:

struct Connection
{
    int type;
    union
    {
        struct Network network;
        struct USB usb;
        struct Virtual virtual;
    }
};

Voorbeeld Gebruik in Libinfinity: http://git.0x539.de/?p=infinote.git;a=blob;f=Libinfinity/common/inf-Session.ciCEh=3E887F0D63BD754C6B5EC232948027CBBF4D61FC;HB=head#l74


Antwoord 5, autoriteit 3%

Ik zou zeggen dat het het gemakkelijker maakt om geheugen te hergebruiken dat op verschillende manieren kan worden gebruikt, d.w.z. geheugen besparen. bijv. je zou een “variant” struct willen doen die zowel een korte string als een nummer kan opslaan:

struct variant {
    int type;
    double number;
    char *string;
};

In een 32-bits systeem zou dit resulteren in het gebruik van ten minste 96 bits of 12 bytes voor elk exemplaar van VARIANT.

Met een union kunt u de grootte verkleinen tot 64 bits of 8 bytes:

struct variant {
    int type;
    union {
        double number;
        char *string;
    } value;
};

Je kunt nog meer besparen als je meer verschillende typen variabelen enz. wilt toevoegen. Het kan waar zijn dat je soortgelijke dingen kunt doen door een lege aanwijzer te casten – maar de unie maakt het een stuk toegankelijker omdat evenals type veilig. Dergelijke besparingen klinken niet enorm, maar u bespaart een derde van het geheugen dat wordt gebruikt voor alle instanties van deze structuur.


Antwoord 6, autoriteit 2%

Het is moeilijk om een ​​specifieke gelegenheid te bedenken waarin je dit soort flexibele structuur nodig hebt, misschien in een berichtenprotocol waarbij je berichten van verschillende groottes zou verzenden, maar zelfs dan zijn er waarschijnlijk betere en programmeervriendelijkere alternatieven.

Unions lijken een beetje op varianttypen in andere talen – ze kunnen maar één ding tegelijk bevatten, maar dat ding kan een int, een float enz. zijn, afhankelijk van hoe je het declareert.

Bijvoorbeeld:

typedef union MyUnion MYUNION;
union MyUnion
{
   int MyInt;
   float MyFloat;
};

MyUnion zal alleen een int OF een float bevatten, afhankelijk van wat je het laatst hebt ingesteld. Dus als je dit doet:

MYUNION u;
u.MyInt = 10;

u heeft nu een int gelijk aan 10;

u.MyFloat = 1.0;

u heeft nu een float gelijk aan 1.0. Het bevat niet langer een int. Het is duidelijk dat als u printf(“MyInt=%d”, u.MyInt); dan krijg je waarschijnlijk een foutmelding, hoewel ik niet zeker ben van het specifieke gedrag.

De grootte van de unie wordt bepaald door de grootte van het grootste veld, in dit geval de float.


Antwoord 7

Vakbonden zijn geweldig. Een slim gebruik van vakbonden die ik heb gezien, is om ze te gebruiken bij het definiëren van een evenement. U kunt bijvoorbeeld besluiten dat een gebeurtenis 32 bits is.

Nu, binnen die 32 bits, wil je misschien de eerste 8 bits aanwijzen als identificatie van de afzender van de gebeurtenis… Soms behandel je de gebeurtenis als een geheel, soms ontleed je het en vergelijk je de componenten . vakbonden geven je de flexibiliteit om beide te doen.

union-evenement
{
 niet-ondertekende lange eventCode;
 unsigned char eventParts[4];
};

Antwoord 8

Hoe zit het met VARIANTdie wordt gebruikt in COM-interfaces? Het heeft twee velden – “type” en een unie met een werkelijke waarde die wordt behandeld afhankelijk van het veld “type”.


Antwoord 9

Ik gebruikte union toen ik codeerde voor embedded apparaten. Ik heb C int die 16 bits lang is. En ik moet de hogere 8 bits en de lagere 8 bits ophalen wanneer ik moet lezen van/opslaan naar EEPROM. Dus ik gebruikte deze manier:

union data {
    int data;
    struct {
        unsigned char higher;
        unsigned char lower;
    } parts;
};

Het hoeft niet te worden verschoven, dus de code is gemakkelijker te lezen.

Aan de andere kant zag ik een oude C++ stl-code die union gebruikte voor stl allocator. Als je geïnteresseerd bent, kun je de sgi stl-broncode lezen. Hier is een stukje ervan:

union _Obj {
    union _Obj* _M_free_list_link;
    char _M_client_data[1];    /* The client sees this.        */
};

Antwoord 10

  • Een bestand met verschillende recordtypen.
  • Een netwerkinterface met verschillende soorten verzoeken.

Kijk hier eens naar: Afhandeling van X.25-buffercommando’s

Een van de vele mogelijke X.25-commando’s wordt in een buffer ontvangen en ter plekke afgehandeld door een UNION van alle mogelijke structuren te gebruiken.


Antwoord 11

union worden gebruikt om geheugen te besparen, vooral gebruikt op apparaten met beperkt geheugen waar geheugen belangrijk is.
Exp:

union _Union{
  int a;
  double b;
  char c;
};

Laten we bijvoorbeeld zeggen dat we de bovenstaande 3 datatypes (int,double,char) nodig hebben in een systeem waar het geheugen beperkt is.Als we “union” niet gebruiken, moeten we deze 3 datatypes definiëren. In dit geval wordt sizeof(a) + sizeof(b) + sizeof(c) geheugenruimte toegewezen. Maar als we ui gebruiken, wordt er slechts één geheugenruimte toegewezen volgens het grootste gegevenstype in deze 3 gegevenstypen.Omdat alle variabelen in de uniestructuur gebruiken dezelfde geheugenruimte. Daarom zal de geheugenruimte die is toegewezen volgens het grootste gegevenstype gemeenschappelijke ruimte zijn voor alle variabelen.
Bijvoorbeeld:

union _Union{
int a;
double b;
char c;
};
int main() {
 union _Union uni;
 uni.a = 44;
 uni.b = 144.5;
 printf("a:%d\n",uni.a);
 printf("b:%lf\n",uni.b);
 return 0;
 }

Uitvoer is:
een: 0
en b:144.500000

Waarom is a nul?. Omdat de uniestructuur slechts één geheugengebied heeft en alle gegevensstructuren dit gemeenschappelijk gebruiken. Dus de laatst toegewezen waarde overschrijft de oude.
Nog een voorbeeld:

union _Union{
    char name[15];
    int id;
};
int main(){
   union _Union uni;
   char choice;
   printf("YOu can enter name or id value.");
   printf("Do you want to enter the name(y or n):");
   scanf("%c",&choice);
   if(choice == 'Y' || choice == 'y'){
     printf("Enter name:");
     scanf("%s",uni.name);
     printf("\nName:%s",uni.name);
   }else{
     printf("Enter Id:");
     scanf("%d",&uni.id);
     printf("\nId:%d",uni.id);
   }
return 0;
}

Opmerking: de grootte van de unie is de grootte van het grootste veld, omdat er voldoende aantal bytes moet worden gereserveerd om het grootste veld op te slaan.


Antwoord 12

Een eenvoudig en zeer handig voorbeeld is….

Stel je voor:

je hebt een uint32_t array[2]en je wilt toegang tot de 3e en 4e Byte van de Byte-keten.
je zou kunnen doen *((uint16_t*) &array[1]).
Maar dit overtreedt helaas de strikte aliasingregels!

Maar met bekende compilers kunt u het volgende doen:

union un
{
    uint16_t array16[4];
    uint32_t array32[2];
}

technisch gezien is dit nog steeds een overtreding van de regels. maar alle bekende standaarden ondersteunen dit gebruik.


Antwoord 13

Gebruik een unie als je een functie hebt waarbij je een waarde retourneert die kan verschillen, afhankelijk van wat de functie deed.

Other episodes