2009-11-16 41 views
3

可能重複:
Difference between a Structure and a Union in C聯合體與結構體有什麼不同?其他語言是否有類似的結構?

我看到在C聯合這樣的代碼:

union time 
    { 
     long simpleDate; 
     double perciseDate; 
    } mytime; 

是什麼工會,在C結構之間的區別?你會在哪裏使用工會,它有什麼好處? Java,C++和/或Python中是否有類似的構造?

+3

dupe:http://stackoverflow.com/questions/346536/difference-between-a-structure-and-a-union-in-c – 2009-11-16 15:09:56

+1

在技術上不是一個騙局,因爲有關於問題的第二部分其他語言 – 2009-11-16 19:19:00

回答

11

所以,在你的榜樣,當我分配時間:

int main() 
{ 
    time t; 
} 

編譯器可以在&牛逼解釋的內存,如果它可以是一個長:

t.simpleDate; 

或者如果其雙:

t.perciseDate; 

所以,如果內存在t的原始十六進制看起來像

0x12345678; 

該值可以「解析」爲雙精度或長精度,具體取決於它的訪問方式。所以爲了它是有用的,你必須知道一個長和一雙將如何打包&格式化正好在內存中。例如,一個long將是一個2-s補碼的有符號整數,你可以閱讀here。你可以學習如何在二進制here格式化一個雙。

但是,一個結構只是將單獨的變量分組,並將不同的地址空間分成一塊內存。

(請注意您的例子可能是危險的,因爲的sizeof(長)可能是32位,而的sizeof(雙)始終是64位),當你想要一個「原始」表示(比如一個char

工會常用數組)和一個「消息」表示。例如,要通過套接字發送的消息:

struct Msg 
{ 
    int msgType; 
    double Val1; 
    double Val2; 
}; // assuming packing on 32-bit boundary 

union 
{ 
    Msg msg; 
    unsigned char msgAsBinary[20]; 
}; 

希望有所幫助。

+0

這是一個比當前發佈的更好的答案。 – 2009-11-16 15:13:32

+7

「因爲它很有用,所以你必須知道長和雙將如何打包和格式化」。工會的一種使用(不受標準保證,但由大多數編譯器保證)是編寫一個成員,然後讀回另一個成員以得到一種重新解釋演員。爲了這個用途,你需要知道存儲表示。然而,還有另外一個(最初打算的)用途,那就是你存儲哪個成員,記住你存儲的內容,並回讀同一個成員。目的是爲了節省內存,當你永遠不會需要兩個。爲此,格式不重要。 – 2009-11-16 15:18:18

+0

@Steve Jessop:另外一個評論(+1)有關鍵點,應該結合到答案中。 – TheBlastOne 2011-07-07 22:11:30

14

聯合的行爲就好像它的所有成員都在內存中的相同位置重疊。

當您想要表示某種「通用」值或可以是任何類型的值時,這非常有用。由於這些字段重疊,因此只有在您知道之前已初始化的情況下才能合法訪問該字段。不過,因爲C不檢查這一點,許多編譯器發出的代碼,允許它,它是一種常見的伎倆做......有趣的類型轉換,如:

union { 
int integer; 
float real; 
} convert; 

convert.real = 3.14; 
printf("The float %f interpreted as an integer is %08x", convert.real, convert.integer); 

對於更良好的使用,在那裏你跟蹤哪些是最後存儲在工會,它可能看起來比如像這樣:

typedef enum { INTEGER = 0, REAL, BOOLEAN, STRING } ValueType; 

typedef struct { 
    ValueType type; 
    union { 
    int integer; 
    float real; 
    char boolean; 
    char *string; 
    } x; 
} Value; 

這裏應注意,工會實際上是在周圍結構,Value的字段。訪問可能看起來像這樣:

void value_set_integer(Value *value, int x) 
{ 
    value->type = INTEGER; 
    value->x.integer = x; 
} 

這記錄聯合的當前內容是一個整數,並存儲給定的值。一個功能,例如打印Value可以檢查type成員,做正確的事情:

void value_print(const Value *value) 
{ 
    switch(value->type) 
    { 
    case INTEGER: 
    printf("%d\n", value->x.integer); 
    break; 
    case REAL: 
    printf("%g\n", value->x.real); 
    break; 
    /* ... and so on ... */ 
    } 
} 

有一個在Java中沒有等價物。 C++幾乎是C的一個超集,具有相同的功能。它甚至是「單獨」C的實現,並允許anonymous unions。在C++中,上面可能沒有命名內聯(x),這會使代碼縮短很多。

+0

重疊有問題嗎? – SjB 2009-11-16 15:11:06

+0

重疊的問題是你不知道最後寫了什麼。除了少數幾個孤立的實例外,它們都很危險,但它們非常方便。 – 2009-11-16 15:13:01

+0

+1對於「重疊」這個措詞來說,這可能是說出什麼是工會的最優雅的方式。 – 2009-11-16 15:43:35

1

一個聯合可以用來存儲它的任何一個成員,但是(不像一個結構)同時只能有一個。您可以將其視爲包含足夠空間來存儲其最大的成員,併爲您實際分配值的成員重新使用相同的存儲空間。

C++也有工會。 Java沒有。 Python中的對象成員與C完全不同,它們存儲在字典中,而不是連續地放在內存中。我不知道Python是否在某處有一些方便的庫類,它有點像聯合體,但它不像C中那樣是對象。

1

對於每個數據項具有自己的內存位置的結構,但對於聯合,每次只使用一個項目,並且爲每個項目分配的內存位於共享內存中。只有一個內存位置將被工會的數據項共享。工會的規模將是最大變量的大小。

這可能是有益的,因爲有時我們可能不需要複雜數據結構的所有(相關)數據項的數據,並且一次只能存儲/訪問一個數據項。聯盟在這種情況下有幫助。

2

聯合允許您以多種不同方式解釋一個內存位置(原始值,二進制值)。

我實際使用的一個例子是訪問uint32的單個字節。

union { 
    uint32 int; 
    char bytes[4]; 
} uint_bytes; 

聯盟提供的是多種方式訪問​​(部分)相同的內存。

聯合類型的大小等於聯合中最大類型的大小。

2

聯合是一種節省空間的方式來存儲幾種不同類型中的一種。它沒有提供重新發現存儲在其中的類型的機制;這必須在線外確定。從技術上講,訪問聯合中的「錯誤」類型(即沒有初始化的類型)會導致未定義的行爲;在實踐中,它通常會導致比特級的轉換,並且經常被用作這樣做的一種方式。雖然「聯合」類型是C++(C++是C的超集),但大多數C++類型不能安全地存儲在一箇中(具體而言,聯合只能保存POD types,即具有默認拷貝構造函數,缺省析構函數的類並沒有虛擬方法)。如果您想要一個節省空間,基於堆棧的等效於C++中的聯合,能夠存儲複雜對象,請嘗試Boost.Variant

在不太關心堆棧分配的其他語言中,多態性完成了工會的工作。在Java中,所有東西都是從一個Object繼承的,所以Object *可以用來表示的任何對象;或者可以使用公共超類或接口來將對象集合限制爲支持特定操作集合的對象。

在Python中,任何變量都可以包含任何對象,所以從某種意義上說,所有變量都是聯合。您通常不需要確定存儲在變量中的類型;而是使用duck typing - 即查找它支持的方法,而不是它實現的類型/接口。

+1

有關如何在Java和Python(結構模塊)中執行位級別轉換的示例將使其成爲最完整的答案。 – 2009-11-16 18:48:57

+0

由於工會嚴格不應該用於位級別的演員,我會說我不會再回答這個問題;) – 2009-11-16 19:21:19

1

只有一個聯合的一個成員可以一次使用,不同於所有成員一起駐留在內存中的結構。爲聯合空間分配其包含的最長元素的大小。

相關問題