这是一个C11匿名结构体吗?

6

我正在研究C11草案,其中写道:

没有标签的结构类型成员被称为匿名结构;没有标签的联合类型成员被称为匿名联合。匿名结构或联合的成员被视为包含结构或联合的成员。

因此,我构建了以下测试用例:

// struct type with no tag
typedef struct {
  unsigned char a;
  unsigned char b;
  // ... Some other members ...
  unsigned char w;
} AToW;

union
{
  AToW; // <- unnamed member
  unsigned char bytes[sizeof(AToW)];
} myUnion;

Clang和GCC都抱怨无名成员,称声明没有效果。我做错了什么吗?还是它们现在不支持这个功能?


我不认为这就是匿名结构体。请注意“标签”这个词。它是结构体或联合体的 类型 标签,例如 struct foo { ... } f; - 这里“foo”就是标签。 - The Paramagnetic Croissant
@user3477950 是的,AToW 没有标签。 - Johannes Schaub - litb
1
值得注意的是,Clang和GCC似乎都允许您使用AToW作为扩展,以便与Plan9和Microsoft兼容。https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields - hmijail
1个回答

8

不,那不是一个未命名成员。

一个例子是:

struct outer {
    int a;
    struct {
        int b;
        int c;
    };
    int d;
};

包含成员 bc 的内部结构是 struct outer 的一个 未命名成员。这个未命名成员的成员 bc 被认为是包含结构的成员。

这可能比包含结构更有用,特别是可以用于定义类似 Pascal 或 Ada 变体记录的东西:

enum variant_type { t_int, t_double, t_pointer, t_pair };
struct variant {
    enum variant_type type;
    union {
        int i;
        double d;
        void *p;
        struct {
            int x;
            int y;
        };
    };
};

这使得您可以直接将idp作为struct variant对象的成员进行引用,而不是为变量部分创建人工名称。如果某些变量需要多个成员,则可以在匿名联合体中嵌套匿名结构。
(与Pascal和Ada不同的是,在C语言中没有机制来强制执行给定type成员的值哪个变量处于活动状态;这就是C语言。)
在您的示例中,AToW是您之前定义的结构类型的typedef。您不允许有一个裸的
AToW;

在结构体定义中,不能像裸指针那样有任意数量的裸字段。
int;

C11增加了在另一个结构体内定义嵌套匿名结构的功能,但是只能通过在该点定义新的匿名结构类型来实现。您不能有以前定义的类型的匿名结构成员。语言本身可以允许这样做,并且语义(我认为)相当简单明了,但是定义两种不同的方式做同一件事情并没有太多意义。(对于上面的“struct”,请阅读“struct或union”。)
引用N1570 draft(非常接近发布的2011 ISO C标准)第6.7.2.1段第13款:
未命名成员的类型说明符是具有无标记的结构说明符的结构体成员称为匿名结构;类型说明符为具有无标记的联合说明符的未命名成员称为匿名联合。匿名结构或联合的成员被视为包含结构或联合的成员。如果包含结构或联合也是匿名的,则递归应用此规则。
一个结构体说明符包含关键词 struct ,后跟可选的标识符(在本例中省略了标签),后跟用{}括起来的一系列声明。在您的情况下,AToW是一个类型名称,不是一个结构体说明符,因此不能用于定义匿名结构体。

我没有看到与我的情况有什么不同,除了你使用结构体说明符作为类型,而我使用普通标识符作为类型。为什么我的 AToW; 不是一个匿名成员?如果我将其更改为 AToW x;,它将变成一个命名成员。 - Johannes Schaub - litb
@JohannesSchaub-litb:请查看我回答的最后一段更新内容。(简而言之:因为标准规定如此。) - Keith Thompson
“在结构定义中间,你不能像int一样拥有一个裸的AToW;”这句话不允许吗?它说:“没有标记的结构类型的未命名成员称为匿名结构;没有标记的联合类型的未命名成员称为匿名联合”,并继续定义其语义。所以问题归结为“为什么AToW;不是匿名结构?”我还没有看到。 "int;"不是,因为"int"不是结构类型,这很容易理解。 - Johannes Schaub - litb
1
谢谢,看起来新的草案已经解决了这个问题。整个混淆是因为我和一个朋友的交谈,他告诉我 struct A { struct B; }; 会包含一个匿名结构体。这将与C++不兼容,所以我想查一下,并发现可以使用 typedef。但似乎我使用的是太旧的草案。 - Johannes Schaub - litb
@JohannesSchaub-litb:出于好奇,是哪个草案? - Keith Thompson
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接