2011-01-20 22 views

Trả lời

11

Bạn có thể sử dụng bất kỳ loại dữ liệu nào trong liên minh, không có giới hạn.

Khi sử dụng các công đoàn trên cấu trúc, cấu trúc bố trí dữ liệu tuần tự trong bộ nhớ. Điều này có nghĩa là tất cả các thành phần phụ của chúng là riêng biệt.

Công đoàn, mặt khác, sử dụng cùng một bộ nhớ cho tất cả các thành phần phụ của chúng để chỉ có thể tồn tại một bộ phận tại một thời điểm.

Ví dụ:

        +-----+-----+ 
struct { int a; float b } gives | a | b | 
           +-----+-----+ 
            ^ ^
            |  | 
       memory location: 150 154 
            | 
            V 
           +-----+ 
union { int a; float b } gives | a | 
           | b | 
           +-----+ 

cấu trúc được sử dụng khi một "đối tượng" bao gồm các đối tượng khác, giống như một đối tượng điểm gồm hai số nguyên, những là x và y tọa độ:

typedef struct { 
    int x;   // x and y are separate 
    int y; 
} tPoint; 

Các công đoàn thường được sử dụng trong trường hợp một đối tượng có thể là một trong nhiều thứ nhưng chỉ một đối tượng, chẳng hạn như hệ thống lưu trữ loại ít:

typedef enum { STR, INT } tType; 
typedef struct { 
    tType typ;   // typ is separate. 
    union { 
     int ival;  // ival and sval occupy same memory. 
     char *sval; 
    } 
} tVal; 

Chúng hữu ích cho việc tiết kiệm bộ nhớ mặc dù ngày càng ít quan tâm hơn (ngoài công việc ở mức thấp như hệ thống nhúng) nên bạn không thấy nhiều.

+0

Công đoàn không phải để lưu bộ nhớ: chúng thể hiện một loại tổng * *, tức là. một loại nắm giữ ví dụ. * hoặc * một float * hoặc * một int. Các công đoàn rất khó sử dụng và khá hạn chế. Thay vào đó, hãy xem xét sử dụng 'boost :: variant'. –

+11

Tôi e là tôi phải không đồng ý với khá nhiều điều đó, @Alexandre :-) Họ _are_ (thậm chí bây giờ) hữu ích cho việc tiết kiệm bộ nhớ đặc biệt là trong thế giới nhúng nhỏ. Chúng không khó sử dụng nếu bạn hiểu bố cục nằm bên dưới (bao gồm cả các lỗ hổng được triển khai thực hiện) và cho đến khi một cổng nào đó tăng lên C (kiểm tra thẻ), loại biến thể sẽ không được sử dụng nhiều :-) – paxdiablo

+0

Tôi quên 1) rằng đó là C 2) mà mọi người cần phải gần gũi với phần cứng đôi khi. Tuy nhiên, quan điểm của tôi là các công đoàn (trong C++) không nên được sử dụng để đại diện cho các loại tổng hợp. –

4

Vâng, theo tiêu chuẩn ISO/IEC 9899: TC3 (tiêu chuẩn C99):

Một loại công đoàn mô tả một bộ rỗng chồng chéo của các đối tượng thành viên, mỗi người trong số trong đó có một tên tùy theo quy định và có thể phân biệt kiểu.

Tóm lại, không gian bộ nhớ của các thành viên công đoàn trùng lặp và tên bạn cung cấp cho thành viên công đoàn cho phép bạn đọc bộ nhớ ở kích thước vị trí đó. Hãy xem xét:

#include <stdio.h> 
#include <stdint.h> 

typedef union 
{ 
    struct 
    { 
     uint8_t a; 
     uint8_t b; 
     uint8_t c; 
     uint8_t d; 
    }; 
    uint32_t x; 
} somenewtype; 

typedef union 
{ 
    uint32_t* p; 
    uint8_t* q; 
} somepointer; 

int main(int argc, char** argv) 
{ 
    uint32_t r; 
    uint8_t s; 
    somenewtype z; 
    somepointer p; 
    r = 0x11223344; s = 0x11; 
    z.x = 0x11223344; 
    p.p = &r; 
    p.q = &s; 
    printf("%x%x%x%x\n", z.d, z.c, z.b, z.a); 
    printf("%x %x\n", *(p.p), *(p.q)); 
} 

Trong printf đầu tiên, những gì chúng tôi đang làm là in ra các phần 8 bit của số nguyên 32 bit. Hy vọng tất nhiên không có đệm trong cấu trúc vô danh đó.

Trong printf thứ hai? Tôi đã phải bước qua sử dụng gdb để hiểu, nhưng tôi đã làm:

p.p = (uint32_t *) 0x7fffffffde5c; 
p.q = (uint8_t *) 0x7fffffffde5b "\021D3\"\021P\337\377\377\377\177"; 
p.p = (uint32_t *) 0x7fffffffde5b; 

Vâng tất nhiên, con trỏ là tất cả các kích thước tương tự, vì vậy giao p.q ghi đè địa chỉ của p.p. Tôi nghi ngờ mạnh mẽ rằng de-tham chiếu địa chỉ của số nguyên 32-bit cho một con trỏ 8-bit được in "bất cứ điều gì ở vị trí đó + 32 bit trong kích thước" mà đồng tình cho tôi xảy ra là 22334411. Nhưng tôi nghi ngờ, vào thời điểm đó, hành vi là không xác định.

Dù sao, quan điểm rằng tập thể dục ít là để cho bạn thấy rằng:

  • đoàn thể được sử dụng để truy cập vào vị trí bộ nhớ tương tự thông qua một khác nhau "gõ" modifier.
  • Bạn phải cẩn thận những gì bạn làm và hiểu loại cơ bản bạn đang sử dụng. Nếu bạn đang sử dụng con trỏ, hãy cẩn thận sửa đổi của họ khi bạn có thể bắt đầu trỏ đến những người hiểu biết những gì.

Tôi nên chỉ ra rằng tôi có thể thấy việc sử dụng thực tế cho somenewtype nhưng không cho somepointer - đó là một ví dụ giả tạo mà tôi chắc chắn sẽ phá vỡ.

Các vấn đề liên quan