[英]Anonymous union within struct not in c99?
這里是我所遇到的非常簡化的問題代碼:
enum node_type { t_int, t_double }; struct int_node { int value; }; struct double_node { double value; }; struct node { enum node_type type; union { struct int_node int_n; struct double_node double_n; }; }; int main(void) { struct int_node i; i.value = 10; struct node n; n.type = t_int; n.int_n = i; return 0; }
我不明白的是:
$ cc us.c $ cc -std=c99 us.c us.c:18:4: warning: declaration does not declare anything us.c: In function ‘main’: us.c:26:4: error: ‘struct node’ has no member named ‘int_n’
使用沒有-std
選項的GCC
編譯上面的代碼沒有任何問題(類似的代碼工作得很好),但似乎c99
不允許這種技術。 為什么這樣可以使c99
(或c89
, c90
)兼容? 謝謝。
匿名聯合是GNU擴展,不是任何標准版本的C語言的一部分。 對於c99 + GNU擴展,你可以使用-std = gnu99或類似的東西,但最好寫出適當的C而不依賴於只提供語法糖的擴展......
編輯:匿名工會在C11中添加,因此它們現在是該語言的標准部分。 據推測,GCC的-std=c11
可以讓你使用它們。
我發現這個問題大約在其他人做了一年半之后,所以我可以給出一個不同的答案:匿名結構不符合C99標准,但它們符合C11標准。 GCC和clang已經支持這一點(C11標准似乎已經取消了微軟的功能,並且GCC已經為一些MSFT擴展提供了一段時間的支持)。
好吧,解決方案是命名union的實例(可以作為數據類型保持匿名),然后使用該名稱作為代理。
$ diff -u old_us.c us.c --- old_us.c 2010-07-12 13:49:25.000000000 +0200 +++ us.c 2010-07-12 13:49:02.000000000 +0200 @@ -15,7 +15,7 @@ union { struct int_node int_n; struct double_node double_n; - }; + } data; }; int main(void) { @@ -23,6 +23,6 @@ i.value = 10; struct node n; n.type = t_int; - n.int_n = i; + n.data.int_n = i; return 0; }
現在它編譯為c99
沒有任何問題。
$ cc -std=c99 us.c $
僅用於澄清匿名struct
或匿名union
。
6.7.2.1結構和聯合說明符
類型說明符是沒有標記的結構說明符的未命名成員稱為匿名結構 ; 一個未命名的成員,其類型說明符是一個沒有標記的聯合說明符,稱為匿名聯合 。 匿名結構或聯合的成員被視為包含結構或聯合的成員。 如果包含的結構或聯合也是匿名的,則遞歸應用。
C99 沒有匿名結構或聯合
簡化: 類型說明 符標識符 {
聲明列表 }
標記 ;
struct
或union
; struct
或union
自定義名稱; struct
和匿名union
typedef
,則Tags是別名而不是Tags 。 它只是一個匿名struct
或匿名union
只有它沒有標識符和標記,並且存在於另一個struct
或union
內部。
struct s {
struct { int x; }; // Anonymous struct, no identifier and no tag
struct a { int x; }; // NOT Anonymous struct, has an identifier 'a'
struct { int x; } b; // NOT Anonymous struct, has a tag 'b'
struct c { int x; } C; // NOT Anonymous struct
};
struct s {
union { int x; }; // Anonymous union, no identifier and no tag
union a { int x; }; // NOT Anonymous union, has an identifier 'a'
union { int x; } b; // NOT Anonymous union, has a tag 'b'
union c { int x; } C; // NOT Anonymous union
};
typedef
hell:如果你有一個typedef
標簽部分不再是一個標簽,它就是該類型的別名。
struct a { int x; } A; // 'A' is a tag
union a { int x; } A; // 'A' is a tag
// But if you use this way
typedef struct b { int x; } B; // 'B' is NOT a tag. It is an alias to struct 'b'
typedef union b { int x; } B; // 'B' is NOT a tag. It is an alias to union 'b'
// Usage
A.x = 10; // A tag you can use without having to declare a new variable
B.x = 10; // Does not work
B bb; // Because 'B' is an alias, you have to declare a new variable
bb.x = 10;
下面的例子只是改變了union
struct
,工作方式相同。
struct a { int x; }; // Regular complete struct type
typedef struct a aa; // Alias 'aa' for the struct 'a'
struct { int x; } b; // Tag 'b'
typedef struct b bb; // Compile, but unusable.
struct c { int x; } C; // identifier or struct name 'c' and tag 'C'
typedef struct { int x; } d; // Alias 'd'
typedef struct e { int x; } ee; // struct 'e' and alias 'ee'
另一種解決方案是將公共標頭值( enum node_type type
)放入每個結構中,並使您的頂級結構成為聯合。 它並不完全是“不要重復自己”,但它確實避免了匿名聯合和不舒服的代理值。
enum node_type {
t_int, t_double
};
struct int_node {
enum node_type type;
int value;
};
struct double_node {
enum node_type type;
double value;
};
union node {
enum node_type type;
struct int_node int_n;
struct double_node double_n;
};
int main(void) {
union node n;
n.type = t_int; // or n.int_n.type = t_int;
n.int_n.value = 10;
return 0;
}
聯盟必須有一個名稱,並聲明如下:
union UPair {
struct int_node int_n;
struct double_node double_n;
};
UPair X;
X.int_n.value = 12;
查看C99的6.2.7.1,我發現標識符是可選的:
struct-or-union-specifier:
struct-or-union identifier-opt { struct-declaration-list }
struct-or-union identifier
struct-or-union:
struct
union
struct-declaration-list:
struct-declaration
struct-declaration-list struct-declaration
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
specifier-qualifier-list:
type-specifier specifier-qualifier-list-opt
type-qualifier specifier-qualifier-list-opt
我一直在尋找,並且找不到任何匿名工會違反規范的提法。 整個-opt后綴表示該東西,在這種情況下identifier
是6.1的可選項。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.