Neden C Sendikalarına ihtiyacımız var?


236

Sendikalar ne zaman kullanılmalıdır? Neden onlara ihtiyacımız var?

Yanıtlar:


252

Sendikalar genellikle tamsayıların ve şamandıraların ikili gösterimleri arasında dönüştürme yapmak için kullanılır:

union
{
  int i;
  float f;
} u;

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

Bu, C standardına göre teknik olarak tanımlanmamış bir davranış olsa da (yalnızca en son yazılan alanı okumalısınız), hemen hemen her derleyicide iyi tanımlanmış bir şekilde hareket edecektir.

Sendikalar bazen C'de psödo-polimorfizmi uygulamak için, ne tür bir nesne içerdiğini gösteren bir yapı vererek ve sonra olası türleri bir araya getirerek kullanılır:

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;
  }
}

Bu, boyutun struct S28 yerine yalnızca 12 bayt olmasını sağlar .


uf yerine uy olmalı
Amit Singh Tomar

1
Şamandırayı tam sayıya dönüştürmeyi öngören örnek işe yarıyor mu? Böyle düşünmüyorum, int ve float bellekte farklı formatlarda depolandığından. Örneğinizi açıklayabilir misiniz?
spin_eight

3
@spin_eight: Şamandıradan int'e "dönüştürülmüyor". Daha çok "bir şamandıranın ikili gösterimini bir int gibi yeniden yorumlamak" gibi. Çıktı 3 değil: ideone.com/MKjwon Adam'ın neden onaltılı olarak yazdırdığından emin değilim.
endolith

@Adam Rosenfield ben gerçekten dönüşüm altında değildi verim bir tamsayı alamadım: p
Canavar

2
Tanımsız davranışın reddedilmesi gerektiğini hissediyorum. Aslında, tanımlanmış bir davranıştır. C99 standardının 82. dipnotuna bakın: Bir birleşim nesnesinin içeriğine erişmek için kullanılan üye, nesnede bir değeri saklamak için en son kullanılan üyeyle aynı değilse, değerin nesne temsilinin uygun kısmı, yeniden yorumlanır 6.2.6'da açıklandığı gibi yeni tipte bir nesne temsili (bazen "sinsi" olarak adlandırılan bir işlem). Bu bir tuzak temsili olabilir.
Christian Gibbons

136

Sendikalar Gömülü programlamada veya donanıma / belleğe doğrudan erişimin gerekli olduğu durumlarda özellikle kullanışlıdır. İşte önemsiz bir örnek:

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

Sonra reg'e aşağıdaki gibi erişebilirsiniz:

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

Endianness (bayt sırası) ve işlemci mimarisi elbette önemlidir.

Bir diğer kullanışlı özellik bit değiştiricidir:

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;

Bu kodla, kayıt / bellek adresindeki tek bir bite doğrudan erişebilirsiniz:

x = reg.bits.b2;

3
Burada @Adam Rosenfield'ın yukarıdaki cevabı ile birlikte cevabınız mükemmel bir tamamlayıcı çifti oluşturuyor: Bir birlik içinde bir yapı kullandığınızı ve bir yapı içinde bir birlik kullandığınızı gösteriyor . Her ikisine de aynı anda ihtiyacım var: Gömülü bir sistemdeki iş parçacıkları arasında C'de bazı süslü mesaj geçişi polimorfizmini uygulamak için bir yapı içindeki sendika içindeki bir yapı ve her iki cevabınızı birlikte görmediğimi fark etmemiştim .
Gabriel Staples

1
Yanılmışım: Bu, bir yapı içindeki bir birlik içindeki bir yapı içinde, yazdığım gibi yazmak için iç içe bırakılmış, en içteki içten en dış seviyeye kadar olan bir birliktir. Farklı veri türlerinin değerlerine izin vermek için en iç düzeyde başka bir birlik eklemek zorunda kaldım.
Gabriel Staples

64

Düşük seviyeli sistem programlama makul bir örnektir.

IIRC, donanım kayıtlarını bileşen bitlerine ayırmak için sendikalar kullandım. Yani, 8 bitlik bir kayda erişebilirsiniz (olduğu gibi, bunu yaptığım gün içinde ;-) bileşen bitlerine.

(Tam sözdizimini unutuyorum ama ...) Bu yapı, bir kontrol kaydına bir kontrol_baytı olarak ya da ayrı bitler aracılığıyla erişilmesine izin verecektir. Belirli bir endianite için bitlerin doğru kayıt bitleriyle eşleşmesini sağlamak önemlidir.

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;

3
Bu mükemmel bir örnek! Bu tekniği gömülü yazılımda nasıl kullanabileceğinize bir örnek: edn.com/design/integrated-circuit-design/4394915/…
rzetterberg

34

Birkaç kütüphanede nesne yönelmiş mirasın yerini aldım.

Örneğin

        Connection
     /       |       \
  Network   USB     VirtualConnection

Connection "sınıfının" yukarıdakilerden biri olmasını istiyorsanız, şöyle bir şey yazabilirsiniz:

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

Libinfinity ile örnek kullanım: http://git.0x539.de/?p=infinote.git;a=blob;f=libinfinity/common/inf-session.c;h=3e887f0d63bd754c6b5ec232948027cbbf4d61fc;hb=HEAD#l74


33

Sendikalar, birbirini dışlayan veri üyelerinin aynı belleği paylaşmasına izin verir. Bu, gömülü sistemlerde olduğu gibi bellek daha az olduğunda oldukça önemlidir.

Aşağıdaki örnekte:

union {
   int a;
   int b;
   int c;
} myUnion;

Bu birleşim 3 ayrı int değerinden ziyade tek bir int alanının yerini alacaktır. Kullanıcı a değerini ve sonra b değerini ayarlarsa, her ikisi de aynı bellek konumunu paylaştığı için a değerinin üzerine yazar .


29

Birçok kullanım. Sadece grep union /usr/include/*veya benzer dizinlerde yapın. Vakaların çoğu yapının unionbir structve bir üyesine sarılır , birlikte hangi öğeye erişileceğini söyler. Örneğin man elf, gerçek hayat uygulamaları için ödeme .

Temel prensip budur:

struct _mydata {
    int which_one;
    union _data {
            int a;
            float b;
            char c;
    } foo;
} bar;

switch (bar.which_one)
{
   case INTEGER  :  /* access bar.foo.a;*/ break;
   case FLOATING :  /* access bar.foo.b;*/ break;
   case CHARACTER:  /* access bar.foo.c;*/ break;
}

Tam aradığım şey! Bazı üç nokta parametresini değiştirmek için çok yararlı :)
Nicolas Voron

17

İşte benim kendi kod temeli bir sendika örneği (bellekten ve başka bir deyişle tam olmayabilir). Dil öğelerini oluşturduğum bir tercümanda depolamak için kullanıldı. Örneğin, aşağıdaki kod:

set a to b times 7.

aşağıdaki dil öğelerinden oluşur:

  • sembol [grubu]
  • Değişken [a]
  • sembol [için]
  • Değişken [b]
  • sembol [kere]
  • Sabit [7]
  • sembol [.]

Dil unsurları ' #define' değerleri olarak tanımlanmıştır :

#define ELEM_SYM_SET        0
#define ELEM_SYM_TO         1
#define ELEM_SYM_TIMES      2
#define ELEM_SYM_FULLSTOP   3
#define ELEM_VARIABLE     100
#define ELEM_CONSTANT     101

ve her bir elemanı depolamak için aşağıdaki yapı kullanılmıştır:

typedef struct {
    int typ;
    union {
        char *str;
        int   val;
    }
} tElem;

her bir öğenin boyutu, maksimum birleşimin boyutuydu (tip için 4 bayt ve birleşim için 4 bayt, bunlar tipik değerler olsa da, gerçek boyutlar uygulamaya bağlıdır).

Bir "set" öğesi oluşturmak için şunları kullanırsınız:

tElem e;
e.typ = ELEM_SYM_SET;

Bir "değişken [b]" öğesi oluşturmak için şunları kullanırsınız:

tElem e;
e.typ = ELEM_VARIABLE;
e.str = strdup ("b");   // make sure you free this later

Bir "sabit [7]" öğesi oluşturmak için şunları kullanırsınız:

tElem e;
e.typ = ELEM_CONSTANT;
e.val = 7;

ve kolayca şamandıralar ( float flt) veya gerekçeler ( struct ratnl {int num; int denom;}) ve diğer türleri içerecek şekilde genişletebilirsiniz .

Temel dayanak noktası, bellekte bitişik olmaması strve valaslında üst üste gelmemesidir, bu nedenle, burada gösterilen, yapının bellek konumuna dayalı olduğu 0x1010ve tamsayıların ve işaretçilerin her ikisinin de bulunduğu aynı bellek bloğunda farklı bir görünüm elde etmenin bir yoludur. 4 bayt:

       +-----------+
0x1010 |           |
0x1011 |    typ    |
0x1012 |           |
0x1013 |           |
       +-----+-----+
0x1014 |     |     |
0x1015 | str | val |
0x1016 |     |     |
0x1017 |     |     |
       +-----+-----+

Sadece bir yapıda olsaydı şöyle olurdu:

       +-------+
0x1010 |       |
0x1011 |  typ  |
0x1012 |       |
0x1013 |       |
       +-------+
0x1014 |       |
0x1015 |  str  |
0x1016 |       |
0x1017 |       |
       +-------+
0x1018 |       |
0x1019 |  val  |
0x101A |       |
0x101B |       |
       +-------+

Meli make sure you free this lateraçıklama sabiti elemanı çıkarılabilir?
Trevor

Evet, @Trevor, gerçi ben son 4+ yılda onu gören ilk kişi olduğuna inanamıyorum :-) Sabit, ve bunun için teşekkürler.
paxdiablo

7

Farklı şekillerde kullanılabilen hafızanın yeniden kullanılmasını kolaylaştırdığını söyleyebilirim, yani hafıza tasarrufu. Örneğin, kısa bir dizeyi ve bir sayıyı kaydedebilen bir "varyant" yapısı yapmak istersiniz:

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

32 bitlik bir sistemde bu, her bir örnek için en az 96 bit veya 12 bayt kullanılmasına neden olur. variant .

Bir birleşim kullanarak boyutu 64 bit veya 8 bayta kadar azaltabilirsiniz:

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

Daha farklı değişken türleri vb. Eklemek isterseniz daha da fazla tasarruf sağlayabilirsiniz. Doğru bir işaretçi kullanarak benzer şeyler yapabileceğiniz doğru olabilir - ancak birlik, onu hem tür hem de daha erişilebilir hale getirir. kasa. Bu tür tasarruflar kulağa büyük gelmiyor, ancak bu yapının tüm örnekleri için kullanılan belleğin üçte birini tasarruf ediyorsunuz.


5

Bu tür esnek bir yapıya ihtiyacınız olduğunda, belki de farklı boyutlarda mesajlar göndereceğiniz bir mesaj protokolünde belirli bir durumu düşünmek zordur, ancak o zaman bile muhtemelen daha iyi ve daha programcı dostu alternatifler vardır.

Sendikalar diğer dillerdeki değişken türlerine benzer - bir seferde sadece bir şey tutabilirler, ancak bunu nasıl beyan ettiğinize bağlı olarak bir int, bir float vb.

Örneğin:

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

MyUnion, en son ayarladığınıza bağlı olarak yalnızca bir int VEYA float içerir . Yani bunu yapıyor:

MYUNION u;
u.MyInt = 10;

u şimdi 10'a eşit bir int'e sahiptir;

u.MyFloat = 1.0;

u şimdi 1.0'a eşit bir şamandıra tutar. Artık bir int içermiyor. Açıkçası şimdi printf ("MyInt =% d", u.MyInt); belirli davranıştan emin olmadığım halde muhtemelen bir hata alırsınız.

Birliğin büyüklüğü, en büyük alanının, bu durumda şamandıra büyüklüğüne göre belirlenir.


1
sizeof(int) == sizeof(float)( == 32) genellikle.
Nick T

1
Kayıt için, daha sonra int baskı şamandıraya atama olacak değil derleyici ne de çalışma zamanı ortamı ne gibi bir hataya neden bilmesi değeri geçerlidir. Yazdırılan int, elbette çoğu amaç için anlamsız olacaktır. Sadece bir int olarak yorumlanan şamandıranın bellek temsili olacaktır.
Jerry B

4

Sendikalar, donanım, aygıtlar veya ağ protokolleri tarafından tanımlanan yapıları modellemek istediğinizde veya çok sayıda nesne oluşturduğunuzda ve yerden tasarruf etmek istediğinizde kullanılır. Gerçekten de onlara% 95 ihtiyaç duymazsınız, hata ayıklaması kolay kodla sadık kalın.


4

Bu cevapların çoğu, bir türden diğerine döküm ile ilgilidir. Ben sadece daha fazla aynı tür sendikalar en iyi kullanımı (yani bir seri veri akışı ayrıştırırken). Çerçeveli bir paketin ayrıştırılmasını / oluşturulmasını önemsiz hale getirir .

typedef union
{
    UINT8 buffer[PACKET_SIZE]; // Where the packet size is large enough for
                               // the entire set of fields (including the payload)

    struct
    {
        UINT8 size;
        UINT8 cmd;
        UINT8 payload[PAYLOAD_SIZE];
        UINT8 crc;
    } fields;

}PACKET_T;

// This should be called every time a new byte of data is ready 
// and point to the packet's buffer:
// packet_builder(packet.buffer, new_data);

void packet_builder(UINT8* buffer, UINT8 data)
{
    static UINT8 received_bytes = 0;

    // All range checking etc removed for brevity

    buffer[received_bytes] = data;
    received_bytes++;

    // Using the struc only way adds lots of logic that relates "byte 0" to size
    // "byte 1" to cmd, etc...
}

void packet_handler(PACKET_T* packet)
{
    // Process the fields in a readable manner
    if(packet->fields.size > TOO_BIG)
    {
        // handle error...
    }

    if(packet->fields.cmd == CMD_X)
    {
        // do stuff..
    }
}

Düzenle Endianness ve struct padding hakkındaki yorum geçerli ve büyük endişelerdir. Bu kod gövdesini neredeyse tamamen gömülü yazılımda kullandım, çoğu borunun her iki ucunu da kontrol ettim.


1
Aşağıdaki nedenlerden dolayı 2 farklı platformda veri alışverişi yapılıyorsa, bu kod (çoğu zaman) çalışmaz: 1) Endianness farklı olabilir. 2) Yapılarda dolgu.
Mahori

@Ravi Endianness ve dolgu ile ilgili endişelere katılıyorum. Ancak bunu yalnızca gömülü projelerde kullandığım bilinmelidir. Çoğu boruların her iki ucunu da kontrol ettim.
Adam Lewis

1

Sendikalar harika. Gördüğüm sendikaların akıllıca bir kullanımı, bir olay tanımlarken onları kullanmaktır. Örneğin, bir etkinliğin 32 bit olduğuna karar verebilirsiniz.

Şimdi, bu 32 bit içinde, olayı gönderenin tanımlayıcısı olarak ilk 8 biti atamak isteyebilirsiniz ... Bazen olayla bir bütün olarak ilgilenirsiniz, bazen diseksiyon yapar ve bileşenlerini karşılaştırırsınız. sendikalar her ikisini de yapma esnekliği sağlar.

birlik Etkinliği
{
  imzasız uzun eventCode;
  unsigned char eventParts [4];
};

1

Peki ya VARIANTCOM arayüzlerinde kullanılır? İki türü vardır - "tür" ve "tür" alanına bağlı olarak işlenen gerçek değeri tutan bir birlik.


1

Okulda böyle sendikalar kullandım:

typedef union
{
  unsigned char color[4];
  int       new_color;
}       u_color;

Renkleri daha kolay işlemek için kullandım, >> ve << operatörlerini kullanmak yerine, char dizimin farklı dizininden geçmek zorunda kaldım.


1

Gömülü cihazlar için kod yazarken sendika kullandım. 16 bit uzunluğunda C int var. Ve EEPROM'dan okuma / saklamaya ihtiyaç duyduğumda daha yüksek 8 biti ve daha düşük 8 biti almam gerekiyor. Bu şekilde kullandım:

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

Vites değiştirme gerektirmez, böylece kodun okunması daha kolaydır.

Öte yandan, stl ayırıcı için birlik kullanılan bazı eski C ++ stl kodu gördüm. Eğer ilgileniyorsanız, sgi stl kaynak kodunu okuyabilirsiniz . İşte bir parçası:

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

1
/ structCihazınızın etrafında bir gruplamaya ihtiyacınız olmaz mı ? Şu anda her ikisi de sadece ilk baytı göstermelidir. higherlower
Mario

@Mario ah doğru, sadece elle yazıyorum ve unutuyorum, teşekkürler
Mu Qiao

1
  • Farklı kayıt türleri içeren bir dosya.
  • Farklı istek türleri içeren bir ağ arayüzü.

Şuna bir göz atın: X.25 arabellek komutu işleme

Olası birçok X.25 komutundan biri, bir tampona alınır ve olası tüm yapıların BİRLİĞİ kullanılarak yerinde işlenir.


Bu örneklerin her ikisini de açıklar mısınız? Yani bunların sendika ile nasıl ilişkilendirildiği
Amit Singh Tomar

1

C'nin ilk sürümlerinde, tüm yapı bildirimleri ortak bir alan kümesini paylaşırdı. Verilen:

struct x {int x_mode; int q; float x_f};
struct y {int y_mode; int q; int y_l};
struct z {int z_mode; char name[20];};

bir derleyici temelde yapıların boyutlarının (ve muhtemelen hizalamalarının) bir tablosunu ve yapıların üyelerinin adlarının, türlerinin ve ofsetlerinin ayrı bir tablosunu üretir. Derleyici üyeleri hangi yapılara ait olan izlemek vermedi ve iki yapının üyesi ile olduğu gibi (tip ve eşleşen ofset yalnızca aynı isimde bir üye olmasını sağlayacak qbir struct xvestruct y ). P, herhangi bir yapı türüne işaretçi olsaydı, p-> q, işaretçi p'ye "q" ofsetini ekler ve elde edilen adresten bir "int" getirir.

Yukarıdaki semantikler göz önüne alındığında, söz konusu yapılar içindeki yararlı alanlarla dizilmiş olması şartıyla, işlev tarafından kullanılan tüm alanların birbirinin yerine kullanılabilmesi için, birden çok yapı türü üzerinde bazı yararlı işlemler yapabilen bir fonksiyon yazmak mümkün olmuştur. Bu yararlı bir özellikti ve söz konusu yapı türlerine karşı yapı erişimi için kullanılan üyeleri doğrulamak üzere C'yi değiştirmek, aynı adreste birden çok adlandırılmış alan içerebilen bir yapıya sahip olmanın bir yolu olmadığında onu kaybetmek anlamına gelirdi. C'ye "birleşim" türlerinin eklenmesi bu boşluğun bir miktar doldurulmasına yardımcı oldu (olmasa da, IMHO ve olması gerektiği gibi).

Sendikaların bu boşluğu doldurma yeteneğinin önemli bir parçası, bir sendika üyesine yönelik bir işaretçinin, o üyeyi içeren herhangi bir sendikaya bir işaretçiye dönüştürülebilmesi ve herhangi bir sendikaya yönelik bir işaretçinin herhangi bir üyeye bir işaretçiye dönüştürülebilmesiydi. C89 Standart açıkça bir döküm söylemek etmezken T*doğrudan için U*her ikisini de içeren bir birlik türü için bir işaretçi olarak döküm eşdeğerdir Tve Ubu döküm sonra ve U*, ikinci döküm dizisinin tanımlanmış bir davranış ile etkilenecek birleşim türü kullanıldı ve Standart, ' Tden doğrudan yayın için herhangi bir ters anlambilim belirtmedi U. Bundan başka, bir işlev bilinmeyen bir işaretçi ile bir nesne yazma davranışını alınan durumlardaT* ,T*a U*ve ardından nesneyi okumak, U*türden bir üye aracılığıyla bir birleşim yazmaya ve tür Tolarak okumaya eşdeğerdir U; bu, birkaç durumda standart olarak tanımlanır (örneğin Ortak Başlangıç ​​Dizisi üyelerine erişirken) ve Uygulama Tanımlı (daha doğrusu) (tanımlanmamıştan daha). Programların CIS güvencelerini sendika türündeki gerçek nesnelerle sömürmesi nadir olmakla birlikte, bilinmeyen kökenlere yönelik göstergelerin sendika üyelerine işaretçiler gibi davranması ve bunlarla ilişkili davranışsal garantilere sahip olması gerçeğinden yararlanmak çok daha yaygındı.


bunun bir örneğini verebilir misiniz: `` birbirinin yerine birden çok yapı türü üzerinde bazı yararlı işlemler yapabilen bir işlev yazmak mümkün oldu ''. Aynı ada sahip birden çok yapı üyesi nasıl kullanılabilir? Eğer iki yapı aynı veri hizalamasına sahipse ve bu yüzden örneğin örneğinizle aynı ada ve ofsete sahip bir üye varsa, o zaman hangi yapıdan gerçek verileri verirdim? (değer). İki yapı aynı hizalamaya ve aynı üyelere sahiptir, fakat farklı değerlere sahiptir. Lütfen detaylandırabilir misiniz
Çoban

@Herdsman: C'nin ilk sürümlerinde, bir yapı üyesi adı bir tür ve bir sapma içerir. Farklı yapıların iki üyesi, yalnızca türleri ve ofsetleri eşleştiğinde aynı ada sahip olabilir. Yapı elemanı Eğer foobir olan int8 ofset, daha sonra anyPointer->foo = 1234;geliyordu "8 bayt tarafından, yerdeğişime bunu anyPointer adresi almak ve elde edilen adrese değerin 1234 tamsayı deposu gerçekleştirin. Olmadığına derleyici bilmek ya da bakım gerek olmaz anyPointertespit fooüyeleri arasında listelenen herhangi bir yapı türü
supercat

İşaretçi ile, işaretçi 'kökenine' bakılmaksızın herhangi bir adresi dereference edebilirsiniz, bu doğrudur, ancak veri getirebilirsem, yapı üyelerinin tablolarını ve adlarını (yazılarınızda söylediğin gibi) tutan derleyicinin amacı nedir? herhangi bir işaretçi sadece belirli bir yapıdaki bir üyenin adresini bilmek? Derleyici, anyPointerbir yapı üyesi ile kimlik doğrulaması yapıp yapmadığını bilmiyorsa , derleyici to have a member with the same name only if the type and offset matchedyayınınızın bu durumunu nasıl denetler ?
Çoban

@Herdsman: Derleyici, yapı üyelerinin adlarının listesini tutar çünkü kesin davranışı p->foo, türüne ve ofsetine bağlı olacaktır foo. Aslında, p->fookısaydı *(typeOfFoo*)((unsigned char*)p + offsetOfFoo). İkinci sorunuza gelince, bir derleyici bir yapı üyesi tanımıyla karşılaştığında, bu ada sahip bir üye bulunmamasını veya bu ada sahip üyenin aynı tür ve ofsete sahip olmasını gerektirir; Eşleşmeyen bir yapı üyesi tanımı mevcut olsaydı, squawked olurdu tahmin ediyorum, ama nasıl hataları ele bilmiyorum.
supercat

0

Basit ve çok kullanışlı bir örnek ....

Hayal etmek:

Eğer bir var uint32_t array[2]ve Byte zincirinin 3. ve 4. Byte erişmek istediğiniz. yapabilirsin *((uint16_t*) &array[1]). Ama bu ne yazık ki katı takma kurallara aykırı!

Ancak bilinen derleyiciler aşağıdakileri yapmanızı sağlar:

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

teknik olarak bu hala kuralların ihlalidir. ancak bilinen tüm standartlar bu kullanımı desteklemektedir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.