结构体中的匿名联合不在 c99 中?

发布于 2024-09-08 18:10:48 字数 815 浏览 6 评论 0原文

这是我遇到的问题的非常简化的代码:

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)?谢谢。

here is very simplified code of problem I have:

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;
}

And what I don't undestand is this:

$ 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’

Using GCC without -std option compiles code above without any problems (and the similar code is working pretty well), but it seems that c99 does not permit this technique. Why is it so and is it possible to make is c99 (or c89, c90) compatible? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

帅的被狗咬 2024-09-15 18:10:49

Union 必须有一个名称并声明如下:

union UPair {
    struct int_node int_n;
    struct double_node double_n;
};

UPair X;
X.int_n.value = 12;

Union must have a name and be declared like this:

union UPair {
    struct int_node int_n;
    struct double_node double_n;
};

UPair X;
X.int_n.value = 12;
青衫负雪 2024-09-15 18:10:49

另一个解决方案是将公共标头值(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;
}

Another solution is to put the common header value (enum node_type type) into every structure, and make your top-level structure a union. It's not exactly "Don't Repeat Yourself", but it does avoid both anonymous unions and uncomfortable looking proxy values.

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;
}
本王不退位尔等都是臣 2024-09-15 18:10:49

查看 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 是可选的。

Looking at 6.2.7.1 of C99, I'm seeing that the identifier is optional:

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

I've been up and down searching, and cannot find any reference to anonymous unions being against the spec. The whole -opt suffix indicates that the thing, in this case identifier is optional according to 6.1.

对你再特殊 2024-09-15 18:10:48

匿名联合是 GNU 扩展,不属于任何 C 语言标准版本的一部分。您可以对 c99+GNU 扩展使用 -std=gnu99 或类似的东西,但最好编写正确的 C,而不是依赖于只提供语法糖的扩展...

编辑: 匿名联合是添加到 C11 中,因此它们现在已成为该语言的标准部分。大概 GCC 的 -std=c11 允许您使用它们。

Anonymous unions are a GNU extension, not part of any standard version of the C language. You can use -std=gnu99 or something like that for c99+GNU extensions, but it's best to write proper C and not rely on extensions which provide nothing but syntactic sugar...

Edit: Anonymous unions were added in C11, so they are now a standard part of the language. Presumably GCC's -std=c11 lets you use them.

不及他 2024-09-15 18:10:48

我在其他人发现这个问题大约一年半后才发现,所以我可以给出不同的答案:匿名结构不在 C99 标准中,但它们在 C11 标准中。 GCC 和 clang 已经支持这一点(C11 标准似乎已经从 Microsoft 中取消了该功能,并且 GCC 已经为某些 MSFT 扩展提供了一段时间的支持)。

I'm finding this question about a year and a half after everybody else did, so I can give a different answer: anonymous structs are not in the C99 standard, but they are in the C11 standard. GCC and clang already support this (the C11 standard seems to have lifted the feature from Microsoft, and GCC has provided support for some MSFT extensions for some time).

安静 2024-09-15 18:10:48

好吧,解决方案是命名联合实例(可以作为数据类型保持匿名),然后使用该名称作为代理。

$ 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 
$ 

注意:无论如何,我对这个解决方案并不满意。

Well, the solution was to name instance of the union (which can remain anonymous as datatype) and then use that name as a proxy.

$ 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;
 }

Now it compiles as c99 without any problems.

$ cc -std=c99 us.c 
$ 

Note: I am not happy about this solution anyway.

风向决定发型 2024-09-15 18:10:48

只是为了澄清匿名 struct 或匿名 union

C11

6.7.2.1 结构和联合说明符

未命名成员,其类型说明符是结构说明符
无标签称为匿名结构;一个未命名成员,其类型
说明符是一个无标签的联合说明符,称为匿名
联盟。考虑匿名结构或联合的成员
成为包含结构或联合的成员。这适用
如果包含的结构或联合也是匿名的,则递归。


C99 没有匿名结构体或联合体

简化:类型说明符 标识符 { 声明列表 }< /code> 标签 ;

  • 类型说明符structunion;
  • 标识符:可选,您的structunion的自定义名称;
  • 声明列表:成员、变量、匿名struct和匿名union
  • 标签:可选。如果类型说明符前面有typedef,则标签是别名,而不是标签

仅当它没有标识符和标签,并且存在于另一个 structunion< 内时,它才是匿名 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'

Just for clarifications about anonymous struct or anonymous union.

C11

6.7.2.1 Structure and union specifiers

An unnamed member whose type specifier is a structure specifier with
no tag is called an anonymous structure; an unnamed member whose type
specifier is a union specifier with no tag is called an anonymous
union
. The members of an anonymous structure or union are considered
to be members of the containing structure or union. This applies
recursively if the containing structure or union is also anonymous.

C99 There are no anonymous struct or union

Simplified: Type-specifier Identifier { Declaration-list } Tags ;

  • Type-specifier: struct or union;
  • Identifier: optional, your custom name for the struct or union;
  • Declaration-list: members, your variables, anonymous struct and anonymous union
  • Tags: optional. If you have a typedef in front of the Type-specifier, the Tags are alias and not Tags.

It is a anonymous struct or anonymous union only if it have no identifier and no tag, and exist inside another struct or 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: if you have a typedef the tag part is not a tag anymore, it is alias for that type.

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;

The example bellow just change struct for union, work the same way.

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'

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文