【问题标题】:C11 struct inheritance with anonymous structC11 结构继承与匿名结构
【发布时间】:2018-03-28 19:27:31
【问题描述】:

我看到this way 在 C11 中使用匿名struct 实现某种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

这不是在我的编译器中实现的,还是我做错了?

【问题讨论】:

标签: c inheritance gcc struct c11


【解决方案1】:

标准只允许没有标签的结构和联合作为未命名成员:

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 的地址并使用结果指针访问结构,那么该版本的代码将在别名规则的“现代”解释下失败。
【解决方案2】:

您似乎正试图在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 引用的标准部分。

【讨论】:

  • 我明白了。如果无论如何都需要在那里明确定义,那么对内部结构的成员进行分组有什么意义?
  • 这是 100 美元的问题。我对它进行了一些尝试,添加了多个级别和多种类型,但我认为在结构中嵌入未命名的匿名结构没有任何好处。在我看来,只是在原始结构本身中声明变量更有意义。我必须查看标准委员会的会议记录,但我怀疑这是为了在 union 中提供匿名的未命名 struct 以用于 bitfield 的目的,而且您可以使用struct 只是以相同方式处理联合和结构的副作用。
  • @DavidC.Rankin:恕我直言,那里的标准非常可怕,尤其是考虑到“现代”别名规则,该规则假定出现在联合中的未标记结构不会为具有相同成员的标记结构别名.
【解决方案3】:

根据GCC 参考:使用-fms-extensions 标志,这将启用此功能。

  • 除非使用-fms-extensions,否则未命名字段必须是不带标签的结构或联合定义(例如,'struct { 诠释一个; };')。如果使用-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

【讨论】:

    猜你喜欢
    • 2023-03-04
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 2012-02-14
    • 2017-01-13
    • 1970-01-01
    相关资源
    最近更新 更多