簡體   English   中英

struct中的匿名聯合不在c99中?

[英]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 (或c89c90 )兼容? 謝謝。

匿名聯合是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

C11

6.7.2.1結構和聯合說明符

類型說明符是沒有標記的結構說明符的未命名成員稱為匿名結構 ; 一個未命名的成員,其類型說明符是一個沒有標記的聯合說明符,稱為匿名聯合 匿名結構或聯合的成員被視為包含結構或聯合的成員。 如果包含的結構或聯合也是匿名的,則遞歸應用。

C99 沒有匿名結構或聯合

簡化: 類型說明 符標識符 { 聲明列表 } 標記 ;

  • 類型說明符structunion ;
  • 標識符 :可選, structunion自定義名稱;
  • 聲明列表 :成員,變量,匿名struct和匿名union
  • 標簽 :可選。 如果在Type-specifier前面有typedef ,則Tags是別名而不是Tags

它只是一個匿名struct或匿名union只有它沒有標識符和標記,並且存在於另一個structunion內部。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM