Mengapa kita membutuhkan Serikat Pekerja?

236

Kapan serikat harus digunakan? mengapa kita membutuhkan mereka?

timrau
sumber

Jawaban:

252

Serikat pekerja sering digunakan untuk mengkonversi antara representasi biner dari bilangan bulat dan mengapung:

union
{
  int i;
  float f;
} u;

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

Meskipun perilaku ini secara teknis tidak terdefinisi menurut standar C (Anda seharusnya membaca bidang yang baru saja ditulis), ini akan bertindak dengan cara yang terdefinisi dengan baik di hampir semua kompiler.

Serikat pekerja kadang-kadang juga digunakan untuk mengimplementasikan pseudo-polimorfisme dalam C, dengan memberikan struktur beberapa tag yang menunjukkan jenis objek apa yang dikandungnya, dan kemudian menyatukan jenis-jenis yang mungkin bersama:

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

Ini memungkinkan ukuran struct Shanya 12 byte, bukan 28.

Adam Rosenfield
sumber
harus ada kamu sebagai ganti uf
Amit Singh Tomar
1
Apakah contoh yang mengonversi float ke integer berfungsi? Saya kira tidak, karena int dan float disimpan dalam berbagai format dalam memori. Bisakah Anda menjelaskan contoh Anda?
spin_eight
3
@ spin_eight: Ini bukan "mengubah" dari float ke int. Lebih seperti "menafsirkan ulang representasi biner dari float seolah-olah itu adalah int". Outputnya bukan 3: ideone.com/MKjwon Saya tidak yakin mengapa Adam mencetak sebagai hex.
endolith
@ Adam Rosenfield saya tidak terlalu mengerti konversi saya tidak mendapatkan bilangan bulat dalam output: p
The Beast
2
Saya merasa penafian tentang perilaku yang tidak terdefinisi harus dihapus. Ini sebenarnya adalah perilaku yang didefinisikan. Lihat catatan kaki 82 dari standar C99: Jika anggota yang digunakan untuk mengakses konten objek gabungan tidak sama dengan anggota yang terakhir digunakan untuk menyimpan nilai dalam objek, bagian yang sesuai dari representasi objek dari nilai ditafsirkan kembali sebagai representasi objek dalam tipe baru seperti yang dijelaskan dalam 6.2.6 (proses yang kadang-kadang disebut "type punning"). Ini mungkin representasi jebakan.
Christian Gibbons
136

Serikat pekerja sangat berguna dalam pemrograman Tertanam atau dalam situasi di mana akses langsung ke perangkat keras / memori diperlukan. Ini adalah contoh sepele:

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

Maka Anda dapat mengakses reg sebagai berikut:

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

Endianness (urutan byte) dan arsitektur prosesor tentu saja penting.

Fitur lain yang bermanfaat adalah pengubah bit:

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;

Dengan kode ini Anda dapat mengakses secara langsung satu bit di register / alamat memori:

x = reg.bits.b2;
kgiannakakis
sumber
3
Jawaban Anda di sini bersama dengan jawaban @Adam Rosenfield di atas membuat pasangan komplementer yang sempurna: Anda mendemonstrasikan menggunakan struct dalam serikat , dan dia menunjukkan menggunakan serikat dalam sebuah struct . Ternyata saya membutuhkan keduanya sekaligus: sebuah struct dalam gabungan dalam sebuah struct untuk mengimplementasikan beberapa polimorfisme penyampaian pesan mewah di C antara utas pada sistem tertanam, dan saya tidak akan menyadari bahwa seandainya saya tidak melihat kedua jawaban Anda bersama-sama .
Gabriel Staples
1
Saya salah: itu adalah persatuan di dalam sebuah struct di dalam sebuah serikat di dalam sebuah struct, bersarang kiri untuk menulis ketika saya menulis itu, dari tingkat paling dalam bersarang ke tingkat paling luar. Saya harus menambahkan penyatuan lain di tingkat paling dalam untuk memungkinkan nilai dari tipe data yang berbeda.
Gabriel Staples
64

Pemrograman sistem tingkat rendah adalah contoh yang masuk akal.

IIRC, saya telah menggunakan serikat untuk memecah register perangkat keras ke dalam bit komponen. Jadi, Anda dapat mengakses register 8-bit (seperti sebelumnya, pada hari saya melakukan ini ;-) ke dalam bit komponen.

(Saya lupa sintaks yang tepat tapi ...) Struktur ini akan memungkinkan register kontrol untuk diakses sebagai control_byte atau melalui bit individu. Penting untuk memastikan bit memetakan ke bit register yang benar untuk endianness yang diberikan.

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;
Snips
sumber
3
Ini adalah contoh yang bagus! Berikut adalah contoh bagaimana Anda dapat menggunakan teknik ini dalam perangkat lunak yang disematkan: edn.com/design/integrated-circuit-design/4394915/…
rzetterberg
34

Saya telah melihatnya di beberapa perpustakaan sebagai pengganti warisan berorientasi objek.

Misalnya

        Connection
     /       |       \
  Network   USB     VirtualConnection

Jika Anda ingin Koneksi "kelas" menjadi salah satu dari yang di atas, Anda dapat menulis sesuatu seperti:

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

Contoh penggunaan di libinfinity: http://git.0x539.de/?p=infinote.git;a=blob;f=libinfinity/common/inf-session.c;h=3e887f0d63bd754c6b5ec232948027cbbf4d61fc;hb=HEAD#l74

generasi bb
sumber
33

Serikat pekerja memungkinkan anggota data yang saling eksklusif untuk berbagi memori yang sama. Ini cukup penting ketika memori lebih langka, seperti pada sistem embedded.

Dalam contoh berikut:

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

Serikat ini akan mengambil ruang int tunggal, daripada 3 nilai int terpisah. Jika pengguna mengatur nilai a , dan kemudian mengatur nilai b , itu akan menimpa nilai a karena mereka berdua berbagi lokasi memori yang sama.

LeopardSkinPillBoxHat
sumber
29

Banyak penggunaan. Lakukan saja grep union /usr/include/*atau di direktori serupa. Sebagian besar kasus yang uniondibungkus dengan structdan salah satu anggota struct memberitahu elemen mana dalam serikat untuk mengakses. Misalnya checkout man elfuntuk implementasi kehidupan nyata.

Ini adalah prinsip dasar:

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;
}
phoxis
sumber
Persis apa yang saya cari! Sangat berguna untuk mengganti beberapa parameter ellipsis :)
Nicolas Voron
17

Berikut adalah contoh penyatuan dari basis kode saya sendiri (dari memori dan diparafrasekan sehingga mungkin tidak tepat). Itu digunakan untuk menyimpan elemen bahasa dalam juru bahasa yang saya buat. Misalnya, kode berikut:

set a to b times 7.

terdiri dari elemen bahasa berikut:

  • simbol [set]
  • variabel [a]
  • simbol [untuk]
  • variabel [b]
  • simbol [kali]
  • konstan [7]
  • simbol[.]

Elemen bahasa didefinisikan sebagai #definenilai ' ' sebagai berikut:

#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

dan struktur berikut digunakan untuk menyimpan setiap elemen:

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

maka ukuran setiap elemen adalah ukuran serikat maksimum (4 byte untuk typ dan 4 byte untuk union, meskipun itu adalah nilai khas, ukuran sebenarnya tergantung pada implementasi).

Untuk membuat elemen "set", Anda akan menggunakan:

tElem e;
e.typ = ELEM_SYM_SET;

Untuk membuat elemen "variabel [b]", Anda akan menggunakan:

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

Untuk membuat elemen "konstan [7]", Anda akan menggunakan:

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

dan Anda dapat dengan mudah mengembangkannya untuk menyertakan float ( float flt) atau rasional ( struct ratnl {int num; int denom;}) dan tipe lainnya.

Premis dasarnya adalah bahwa strdan valtidak bersebelahan dalam memori, mereka sebenarnya tumpang tindih, jadi ini adalah cara untuk mendapatkan pandangan yang berbeda pada blok memori yang sama, diilustrasikan di sini, di mana struktur didasarkan pada lokasi memori 0x1010dan bilangan bulat dan pointer keduanya 4 byte:

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

Jika hanya dalam struktur, itu akan terlihat seperti ini:

       +-------+
0x1010 |       |
0x1011 |  typ  |
0x1012 |       |
0x1013 |       |
       +-------+
0x1014 |       |
0x1015 |  str  |
0x1016 |       |
0x1017 |       |
       +-------+
0x1018 |       |
0x1019 |  val  |
0x101A |       |
0x101B |       |
       +-------+
paxdiablo
sumber
Haruskah make sure you free this laterkomentar dihapus dari elemen konstan?
Trevor
Ya, @ Trevor, meskipun saya tidak percaya Anda adalah orang pertama yang melihatnya dalam 4+ tahun terakhir :-) Tetap, dan terima kasih untuk itu.
paxdiablo
7

Saya akan mengatakan itu membuatnya lebih mudah untuk menggunakan kembali memori yang mungkin digunakan dengan cara yang berbeda, yaitu menghemat memori. Misalnya Anda ingin melakukan beberapa "varian" struct yang dapat menyimpan string pendek serta nomor:

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

Dalam sistem 32 bit ini akan menghasilkan setidaknya 96 bit atau 12 byte yang digunakan untuk setiap instance dari variant .

Menggunakan gabungan Anda dapat mengurangi ukurannya menjadi 64 bit atau 8 byte:

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

Anda dapat menyimpan lebih banyak lagi jika Anda ingin menambahkan lebih banyak tipe variabel yang lain, dll. Mungkin benar, bahwa Anda dapat melakukan hal serupa dengan menggunakan penunjuk kosong - tetapi serikat membuatnya lebih mudah diakses serta mengetik aman. Penghematan seperti itu tidak terdengar masif, tetapi Anda menghemat sepertiga dari memori yang digunakan untuk semua instance struct ini.

Mario
sumber
5

Sulit untuk memikirkan peristiwa tertentu ketika Anda membutuhkan jenis struktur fleksibel ini, mungkin dalam protokol pesan di mana Anda akan mengirim berbagai ukuran pesan, tetapi meskipun demikian mungkin ada alternatif yang lebih baik dan lebih ramah bagi programmer.

Serikat pekerja agak mirip jenis varian dalam bahasa lain - mereka hanya bisa menampung satu hal pada satu waktu, tetapi benda itu bisa berupa int, float, dll. Tergantung pada cara Anda mendeklarasikannya.

Sebagai contoh:

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

MyUnion hanya akan berisi int ATAU float, tergantung pada yang paling baru Anda atur . Jadi melakukan ini:

MYUNION u;
u.MyInt = 10;

kamu sekarang memegang int sama dengan 10;

u.MyFloat = 1.0;

kamu sekarang memegang float sama dengan 1.0. Itu tidak lagi memiliki int. Jelas sekarang jika Anda mencoba dan melakukan printf ("MyInt =% d", u.MyInt); maka Anda mungkin akan mendapatkan kesalahan, meskipun saya tidak yakin dengan perilaku tertentu.

Ukuran serikat ditentukan oleh ukuran bidang terbesarnya, dalam hal ini pelampung.

Xiaofu
sumber
1
sizeof(int) == sizeof(float)( == 32) biasanya.
Nick T
1
Sebagai catatan, menugaskan float kemudian mencetak int tidak akan menyebabkan kesalahan, karena baik kompiler maupun lingkungan run-time tidak tahu nilai mana yang valid. Int yang dicetak akan, tentu saja, menjadi tidak berarti untuk sebagian besar tujuan. Itu hanya akan menjadi representasi memori dari float, diartikan sebagai int.
Jerry B
4

Serikat pekerja digunakan ketika Anda ingin memodelkan struct yang ditentukan oleh perangkat keras, perangkat atau protokol jaringan, atau ketika Anda membuat sejumlah besar objek dan ingin menghemat ruang. Anda benar-benar tidak membutuhkannya 95% dari waktu, tetap dengan kode debug yang mudah.

Ana Betts
sumber
4

Banyak dari jawaban ini berhubungan dengan casting dari satu tipe ke tipe lainnya. Saya mendapatkan yang paling banyak digunakan dari serikat dengan jenis yang sama hanya lebih dari mereka (yaitu ketika mengurai aliran data serial). Mereka memungkinkan parsing / konstruksi paket berbingkai menjadi sepele.

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

Sunting Komentar tentang endianness dan struct padding adalah valid, dan bagus, perhatian. Saya telah menggunakan kode tubuh ini hampir seluruhnya dalam perangkat lunak tertanam, yang sebagian besar saya kendalikan kedua ujung pipa.

Adam Lewis
sumber
1
Kode ini tidak akan berfungsi (sebagian besar waktu) jika data dipertukarkan di 2 platform yang berbeda karena alasan berikut: 1) Endianness mungkin berbeda. 2) Padding dalam struktur.
Mahori
@Ravi Saya setuju dengan keprihatinan tentang endianness dan padding. Namun harus diketahui bahwa saya telah menggunakan ini secara eksklusif dalam proyek tertanam. Sebagian besar yang saya kendalikan kedua ujung pipa.
Adam Lewis
1

Serikat pekerja itu hebat. Salah satu penggunaan cerdas serikat pekerja yang pernah saya lihat adalah menggunakannya saat mendefinisikan suatu peristiwa. Misalnya, Anda mungkin memutuskan bahwa suatu peristiwa adalah 32 bit.

Sekarang, dalam 32 bit itu, Anda mungkin ingin menetapkan 8 bit pertama sebagai pengidentifikasi pengirim acara ... Kadang-kadang Anda berurusan dengan acara secara keseluruhan, kadang-kadang Anda membedahnya dan membandingkan komponen-komponennya. serikat memberi Anda fleksibilitas untuk melakukan keduanya.

acara serikat
{
  eventCode panjang yang tidak ditandatangani;
  unsigned char eventParts [4];
};
dicroce
sumber
1

Bagaimana dengan VARIANTyang digunakan dalam antarmuka COM? Ini memiliki dua bidang - "tipe" dan serikat yang memegang nilai aktual yang diperlakukan tergantung pada bidang "tipe".

sharptooth
sumber
1

Di sekolah, saya menggunakan serikat pekerja seperti ini:

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

Saya menggunakannya untuk menangani warna lebih mudah, daripada menggunakan >> dan << operator, saya hanya harus melalui indeks yang berbeda dari array char saya.

Zoneur
sumber
1

Saya menggunakan penyatuan saat saya mengkode untuk perangkat yang disematkan. Saya memiliki C int yang panjangnya 16 bit. Dan saya harus mengambil 8 bit yang lebih tinggi dan 8 bit yang lebih rendah ketika saya perlu membaca dari / store ke EEPROM. Jadi saya menggunakan cara ini:

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

Tidak perlu digeser agar kode lebih mudah dibaca.

Di sisi lain, saya melihat beberapa kode C ++ stl lama yang menggunakan union untuk stl pengalokasi. Jika Anda tertarik, Anda dapat membaca kode sumber sgi stl . Ini adalah bagiannya:

union _Obj {
    union _Obj* _M_free_list_link;
    char _M_client_data[1];    /* The client sees this.        */
};
Mu Qiao
sumber
1
Tidakkah Anda membutuhkan pengelompokan di structsekitar higher/ lower? Saat ini keduanya harus menunjuk ke byte pertama saja.
Mario
@Mario ah benar, saya hanya menulisnya dengan tangan dan melupakannya, terima kasih
Mu Qiao
1
  • File yang berisi berbagai jenis rekaman.
  • Antarmuka jaringan yang berisi berbagai jenis permintaan.

Lihatlah ini: X.25 penanganan perintah buffer

Salah satu dari banyak perintah X.25 yang mungkin diterima ke dalam buffer dan ditangani dengan menggunakan UNION dari semua struktur yang mungkin.

James Anderson
sumber
bisakah Anda menjelaskan kedua contoh ini. Maksud saya bagaimana ini terkait dengan persatuan
Amit Singh Tomar
1

Dalam versi awal C, semua deklarasi struktur akan berbagi set bidang yang sama. Diberikan:

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

kompiler pada dasarnya akan menghasilkan tabel ukuran struktur (dan mungkin keberpihakan), dan tabel terpisah dari nama, tipe, dan offset anggota struktur. Kompiler tidak melacak anggota mana yang termasuk dalam struktur mana, dan akan memungkinkan dua struktur memiliki anggota dengan nama yang sama hanya jika jenis dan offsetnya cocok (seperti dengan anggota qdari struct xdan struct y). Jika p adalah pointer ke tipe struktur apa pun, p-> q akan menambahkan offset "q" ke pointer p dan mengambil "int" dari alamat yang dihasilkan.

Mengingat semantik di atas, adalah mungkin untuk menulis fungsi yang dapat melakukan beberapa operasi yang bermanfaat pada berbagai jenis struktur secara bergantian, asalkan semua bidang yang digunakan oleh fungsi tersebut berbaris dengan bidang yang berguna dalam struktur yang dimaksud. Ini adalah fitur yang berguna, dan mengubah C untuk memvalidasi anggota yang digunakan untuk akses struktur terhadap jenis struktur yang dimaksud akan berarti kehilangannya dengan tidak adanya sarana memiliki struktur yang dapat berisi beberapa bidang bernama pada alamat yang sama. Menambahkan tipe "union" ke C membantu mengisi celah itu (meskipun tidak, IMHO, dan memang seharusnya demikian).

Bagian penting dari kemampuan serikat untuk mengisi celah itu adalah fakta bahwa penunjuk ke anggota serikat dapat dikonversi menjadi penunjuk ke serikat mana pun yang mengandung anggota itu, dan penunjuk ke serikat mana pun dapat dikonversi menjadi penunjuk ke anggota mana pun. Sementara Standar C89 tidak secara tegas mengatakan bahwa casting T*langsung ke U*setara dengan casting itu ke pointer ke setiap jenis serikat yang mengandung keduanya Tdan U, dan kemudian casting itu untuk U*, tidak ada perilaku yang pasti dari urutan pemain terakhir yang akan dipengaruhi oleh jenis serikat yang digunakan, dan Standar tidak menentukan semantik yang bertentangan untuk pemeran langsung dari Thingga U. Lebih lanjut, dalam kasus di mana fungsi menerima pointer dari asal tidak diketahui, perilaku menulis objek melalui T*, mengubahT*ke a U*, dan kemudian membaca objek melalui U*akan sama dengan menulis serikat melalui anggota tipe Tdan membaca sebagai tipe U, yang akan didefinisikan secara standar dalam beberapa kasus (misalnya ketika mengakses anggota Urutan Awal Umum) dan Implementasi-Ditentukan (lebih tepatnya dari Undefined) untuk sisanya. Walaupun jarang ada program untuk mengeksploitasi jaminan CIS dengan objek aktual dari jenis serikat, jauh lebih umum untuk mengeksploitasi fakta bahwa penunjuk ke objek yang tidak diketahui asalnya harus berperilaku seperti penunjuk bagi anggota serikat dan memiliki jaminan perilaku yang terkait dengannya.

supercat
sumber
dapatkah Anda memberikan contoh tentang ini: `adalah mungkin untuk menulis fungsi yang dapat melakukan beberapa operasi yang berguna pada berbagai jenis struktur secara bergantian`. Bagaimana bisa digunakan beberapa struktur anggota dengan nama yang sama? Jika dua struktur memiliki perataan data yang sama dan dengan demikian seorang anggota dengan nama yang sama dan offset yang sama seperti pada contoh Anda, lalu dari struktur mana saya akan menghasilkan data yang sebenarnya? (nilai). Dua struktur memiliki perataan yang sama dan anggota yang sama, tetapi nilai yang berbeda pada mereka. Bisakah Anda menjelaskannya
Gembala
@ Herdsman: Dalam versi awal C, nama anggota struct merangkum suatu tipe dan offset. Dua anggota struktur yang berbeda dapat memiliki nama yang sama jika dan hanya jika jenis dan offsetnya cocok. Jika struct member fooadalah intdengan offset 8, anyPointer->foo = 1234;berarti "mengambil alamat di anyPointer, memindahkannya dengan 8 byte, dan melakukan penyimpanan integer dari nilai 1234 ke alamat yang dihasilkan. Kompilator tidak perlu tahu atau peduli apakah anyPointerdiidentifikasi semua tipe struktur yang telah footerdaftar di antara anggotanya
supercat
Dengan pointer, Anda dapat melakukan dereferensi alamat apa pun terlepas dari 'asal' pointer, itu benar, tapi lalu apa gunanya kompiler untuk menyimpan tabel anggota struktur dan nama mereka (seperti yang Anda katakan dalam posting Anda) jika saya dapat mengambil data dengan pointer apa saja mengetahui alamat anggota dalam struktur tertentu? Dan jika kompiler tidak tahu apakah anyPointerindentifikasi dengan anggota struct, lalu bagaimana kompiler akan memeriksa kondisi to have a member with the same name only if the type and offset matchedposting Anda?
Gembala
@ Herdsman: Kompiler akan menyimpan daftar nama anggota struktur karena perilaku yang tepat p->footergantung pada jenis dan offset foo. Intinya, p->fooadalah singkatan *(typeOfFoo*)((unsigned char*)p + offsetOfFoo). Adapun pertanyaan terakhir Anda, ketika seorang kompiler menemukan definisi anggota struct, itu mensyaratkan bahwa tidak ada anggota dengan nama itu ada, atau bahwa anggota dengan nama itu memiliki jenis dan offset yang sama; Saya akan menebak bahwa akan berkotek jika definisi anggota struct yang tidak cocok ada, tapi saya tidak tahu bagaimana menangani kesalahan.
supercat
0

Contoh sederhana dan sangat berguna adalah ....

Membayangkan:

Anda memiliki uint32_t array[2]dan ingin mengakses Byte ke-3 dan ke-4 dari rantai Byte. Anda bisa melakukannya *((uint16_t*) &array[1]). Tapi ini sayangnya melanggar aturan aliasing yang ketat!

Tetapi kompiler yang dikenal memungkinkan Anda untuk melakukan hal berikut:

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

secara teknis ini masih merupakan pelanggaran aturan. tetapi semua standar yang dikenal mendukung penggunaan ini.

dhein
sumber