C11带有匿名结构体的结构体继承

6

我看到这个方法可以使用C11中的匿名结构体来实现某种struct继承,并想尝试一下。以下是我的代码:

struct struct_a {
    int aa;
};

struct struct_b {
    struct struct_a;
    int bb;
};

int main(void)
{
    volatile struct struct_b my_b;
    my_b.aa = 5; /* not a member of my_b */
    my_b.bb = 6;

}

来自gcc的结果:

$ gcc -std=c11 struct_extend.c 
struct_extend.c:11:20: warning: declaration does not declare anything
     struct struct_a;
                    ^
struct_extend.c: In function ‘main’:
struct_extend.c:18:9: error: ‘volatile struct struct_b’ has no member named ‘aa’
     my_b.aa = 5; /* not a member of my_b */

相关:

$ gcc --version
gcc (Debian 6.3.0-18) 6.3.0 20170516

这是我的编译器没有实现,还是我做错了?


1
可能是What are anonymous structs and unions useful for in C11?的重复问题。 - Tom Karzes
struct struct_b的声明中,你需要在struct struct_a;之后加上一些内容。 - David C. Rankin
与此相关的是:(https://dev59.com/g1cP5IYBdhLWcg3wXIwy#44524573).. 底线是:为了确保你的代码符合标准,你必须使用相当冗长的形式,不幸的是。 - user2371524
如果您使用gcc -std=c++11,它将支持真正的继承... - Bo Persson
3个回答

5
根据GCC参考文献:使用-fms-extensions标志,将启用此功能。
  • 除非使用-fms-extensions,否则未命名字段必须是没有标签的结构或联合定义(例如,'struct { int a; };')。如果使用-fms-extensions,该字段也可以是带有标签的定义,例如'struct foo { int a; };',对先前定义的结构或联合体的引用,例如'struct foo;',或对先前定义的结构或联合类型的typedef名称的引用。

  • 选项-fplan9-extensions使-fms-extensions以及其他两个扩展程序可用。首先,指向结构的指针会自动转换为匿名字段的指针,以进行赋值和函数调用。

我在GCC上使用了以下命令,它工作正常。

gcc -std=c11 -O2 -Wall -fms-extensions -pedantic -pthread ls.c

4
标准只允许结构体和联合体中没有标签的未命名成员存在: 6.7.2.1 Structure and union specifiers - Paragraph 13 一个类型说明符为没有标签的结构体说明符的未命名成员被称为匿名结构体;一个类型说明符为没有标签的联合体说明符的未命名成员被称为匿名联合体。匿名结构体或联合体的成员被认为是包含它们的结构体或联合体的成员。如果包含它们的结构体或联合体也是匿名的,则递归应用此规则。
由于您的代码有标签,因此不符合C语言标准。链接中提供的答案也不更好。遵循标准的方法很繁琐:
struct struct_b {
    union {
        struct struct_a _aa;
        struct { int aa; };
    };
    int bb;
};

这并不是令人印象深刻的内容。也许可以使用宏来避免重复成员声明,但现在已经是代码异味了。


如果有任何东西试图获取 _aa 的地址并使用结果指针访问结构体,那么代码的那个版本在现代别名规则的“解释”下会失败。 - supercat

1

看起来你正在尝试在 struct_b 中创建一个匿名未命名的结构体,其中包含 int aa,类似于以下内容:

#include <stdio.h>

struct struct_b {
    struct {
        int aa;
    };
    int bb;
};

int main(void)
{
    volatile struct struct_b my_b;
    my_b.aa = 5; /* now a member of my_b */
    my_b.bb = 6;

    printf ("my_b.aa: %d\nmy_b.bb: %d\n", my_b.aa, my_b.bb);

    return 0;
}

示例使用/输出

$ ./bin/strc2
my_b.aa: 5
my_b.bb: 6

这直接源于StoryTeller引用的标准章节。

我明白了。如果内部结构体的成员需要在那里显式定义,那么分组内部结构体的成员有什么意义呢? - Gauthier
那是一个价值100美元的问题。我已经玩弄了一下,添加了多个级别和多种类型,但我没有看到在结构体中嵌入未命名的匿名结构的任何好处。对我来说,只是在原始结构体内声明变量更有意义。我必须看到标准委员会的会议记录,才能确定这是否是为了提供union中的匿名未命名struct用于bitfield目的,而使用结构体只是联合和结构体被相同处理方式的副作用。 - David C. Rankin
@DavidC.Rankin:在我看来,标准非常糟糕,特别是考虑到“现代”别名规则,这些规则假定出现在联合体中的未标记结构不会与具有相同成员的标记结构别名。 - supercat

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