2011-12-09 39 views
1

其他然後內存鑄造技巧是有什麼辦法可以使用無標記的工會對於無類型聯合有沒有用(沒有類型標籤)?

(數據類型,明確持有一組類型不是一個標籤聯合之一,

即,一個是被編譯器強制保存關聯的類型標記,並且可能只有該語言才允許獲得正確類型的值)

沒有在容納它的容器中的關聯類型標記?

未標記的工會對類型化工會有什麼其他優勢嗎?

編輯:顯示我的意思例如在Haskell標籤聯合

data U = I Int | S String 

手動在C標籤聯合

enum u_types {INT,STRING}; 
typedef struct { 
    u_types tag; 
    union u{ 
    int i; 
    char s[STRING_BUFFER_SIZE]; 
    } d; 
}tagged union; 

未標記工會在C

union u{ 
    int i; 
    char s[STRING_BUFFER_SIZE]; 
    } d; 
+0

我不確定我是否理解這個問題。使用「untagged」/「untyped」,你的意思是沒有聯合標籤的union:union {int x; };'或*不完整類型*,例如'union something * x;'其中「something」還沒有被聲明?前者將是「未標記的」,它在C語言中有正式的含義。後者可能是「無類型的」,但據我所知,正式地說C中沒有任何東西被稱爲「無類型」。 – Lundin

+0

我的意思是一個c類似的聯合(無類型是一個錯誤,我的意思是未標記的)沒有關聯的標籤(通常是一個在c結構中的枚舉)。而不是像Haskell中的union ADT這樣的東西在枚舉結構中枚舉枚舉 –

+0

?這與ADT有什麼關係?現在我更加明白了。你可以用代碼示例更新你的問題嗎? – Lundin

回答

1

你不如果您只打算定義一個變量,或者在結構中使用它,則需要該標記。

例如:

union 
{ 
    int x; 
    int y; 
} u; 

void test(void) 
{ 
    u.x = 10; 
} 

如果您計劃在多個地方使用它,你只需要在標籤,如果你需要創建一個指向它的指針等

注:上面的答案假設問題是關於標準所稱的標籤。然而,在給出答案後,問題被更新以表明所討論的標籤是用於記錄聯合中的哪些字段是活動的額外類型字段。無標籤工會

5

的一個用途是方便獲取更大的類型更小的部分:

union reg_a { 
    uint32_t full; 
    struct { /* little-endian in this example */ 
    uint16_t low; 
    uint16_t high; 
    } __attribute__((__packed__)); 
}; 
union reg_a a; 
a.full = 0x12345678; /* set all whole 32-bits */ 
a.high = 0xffff;  /* change the upper 16-bits */ 

union pix_rgba { 
    uint32_t pix; /* to access the whole 32-bit pixel at once */ 
    struct { 
    uint8_t red; /* red component only */ 
    uint8_t green; /* green component only */ 
    uint8_t blue; /* blue only */ 
    uint8_t alpha; /* alpha only */ 
    } __attribute__((__packed__)); 
}; 

這些各種各樣的用途不一定完全可移植的,雖然,因爲它們可能取決於類型的特定表示,字節順序等等。但是,它們通常足夠便攜,以至於一個或兩個備用版本將涵蓋所關心的所有平臺,並且它們可能非常有用。

無論如何,即使沒有檢查標籤,存儲在工會中的內容仍然是已知的,並且不需要存儲和更新標籤的額外開銷,那麼未標記的工會也很有用。可能在另一個地方的信息,也可能有其他目的,可能表明聯盟中應該有什麼樣的數據 - 在這種情況下,沒有必要標記聯盟本身。

0

這裏有一個竅門:

static __attribute__((const, always_inline)) 
int32_t floatToIntBits(float f) { 
    union { 
     float value; 
     int32_t bits; 
    }; 
    value = f; 
    return bits; 
} 
1

你已經張貼什麼是「手動標記」是無效的C語法,我想你的意思是它是:

typedef enum {INT,STRING} u_types; 

typedef struct { 
    u_types tag; 
    union u{ 
    int i; 
    char s[1]; 
    } d; 
}tagged_union; 

請注意,正式在C的struct/union 標籤的定義是STRUC/union關鍵字之後的名稱。在你的第二個例子,u聯合標記。這是我很困惑。


你描述爲「標籤聯合」被稱爲一個變種在計算機科學:可容納多種類型的變量。變體在編程時通常會被忽視,特別是在C中。 MISRA-C:2004,規則18.3和18.4禁止使用。

語言與變種的支持,如VB(也可能哈斯克爾?)通常存在,那麼爲:這個變量可以容納任何東西,但你要小心使用它,因爲它是非常低效的。

在C中,變體是不僅效率低,它們是安全隱患。 MISRA-c在規則18.3中認識到這一點:

例如:當一個程序實際上正在存儲另一種類型的值(例如由於中斷)時,它可能試圖從該位置訪問一種類型的數據。這兩種類型的數據在存儲中可能會有不同的排列方式,並會侵犯其他數據。因此,每次使用切換時可能無法正確初始化數據。這種做法在併發系統中特別危險。


所以問題應該是,是否有標籤聯合(變體)的任何用途?不,那裏沒有。我曾經寫過的任何C程序中都沒有使用過單一的程序,但沒有用處。由於C具有空指針,還有在C更好和更安全的方式來創建通用的數據類型:

void ADT_add_generic_type (void* data, some_enum_t type, size_t size);

看看C標準是如何實現的功能的qsort()和bsearch()的一些通用C編程(:1999 7.20.5.1 ISO 9899):很好的例子

void *bsearch (const void *key, 
       const void *base, 
       size_t nmemb, 
       size_t size, 
       int (*compar)(const void *, const void *)); 

說明bsearch函數搜索nmemb個目的, 初始元素,其中通過鹼指向的陣列,用於元素 與鍵指向的對象匹配。的 由size指定所述陣列的每個元件的尺寸。


爲 「無標記」 工會的用途有幾個,但是。數據協議,打包,硬件寄存器訪問等等。請參閱Dmitri的答案。

0

只要你有使用void *一個通用的實現,你可以使用無標記的工會來代替。由於您使用的是void *,因此必須從上下文中瞭解真正的對象類型。

這是一種實現通用數據結構的最便捷方式,例如可以存儲union { void *ptr; unsigned x; }(在沒有uintptr_t的C平臺上)。