ここに私が持っている問題の非常に簡略化されたコードがあります:
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:警告:宣言は何も宣言しません us .c:関数 'main': us.c:26:4:エラー: 'struct node'には 'int_n' という名前のメンバーがありません
-std
オプションなしでGCC
を使用すると、上記のコードは問題なくコンパイルされます(同様のコードはかなりうまく機能します)が、c99
はこの手法を許可しないようです。なぜそうであり、c99
(またはc89
、c90
)と互換性を持たせることができるのですか?ありがとう。
匿名の共用体はGNU拡張であり、C言語の標準バージョンの一部ではありません。-std= gnu99またはc99 + GNU拡張のようなものを使用できますが、適切に記述するのが最善ですCであり、構文上の砂糖だけを提供する拡張機能に依存しない...
編集: C11で匿名の共用体が追加されたため、これらは言語の標準部分になりました。おそらくGCCの-std=c11
を使用できます。
私はこの質問を他のみんなが1年半後に見つけたので、別の答えを出すことができます:匿名の構造体はC99標準ではなく、C11標準です。 GCCとclangは既にこれをサポートしています(C11標準はMicrosoftからこの機能を解除しているようで、GCCはしばらくの間MSFT拡張機能のサポートを提供してきました)。
解決策は、ユニオンのインスタンスに名前を付け(データ型として匿名のままにすることができます)、その名前をプロキシとして使用することでした。
$ 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構造およびユニオン指定子
型指定子がno tagを持つ構造指定子である名前のないメンバーはanonymous structureと呼ばれます;型指定子がno tagを持つ共用体指定子である名前のないメンバーanonymous unionと呼ばれます。匿名構造体または共用体のメンバーは、包含構造体または共用体のメンバーと見なされます。これは、包含構造または共用体も匿名である場合、再帰的に適用されます。
C99匿名の構造体またはユニオンはありません
簡略化:Type-specifierIdentifier{
宣言リスト}
タグ;
struct
またはunion
;struct
またはunion
のカスタム名。struct
および匿名union
typedef
がある場合、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
地獄: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;
次の例では、struct
をunion
に変更するだけで、同じように機能します。
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;
}
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に従ってオプションであることを示します。
ユニオンには名前があり、次のように宣言する必要があります。
union UPair {
struct int_node int_n;
struct double_node double_n;
};
UPair X;
X.int_n.value = 12;