【问题标题】:Reaching named struct in Unnamed union in C在C中的未命名联合中达到命名结构
【发布时间】:2021-03-21 17:58:56
【问题描述】:

我有以下联合和结构的结构

union ab {
    struct {
        int a;
    } a_st;

    struct {
        int b;
    } b_st;
};

typedef struct c {
    union ab;
} c_st;

当试图直接“到达”联合元素时:

c_st c;
printf("%d\n", c.a_st.a);

引发以下编译错误:

错误:'c_st' {aka 'struct c'} 没有名为 'a_st' 的成员

如果我在 'c_st' 结构中提供联合名称(例如 ab_un),它可以工作,但我需要调用 c.ab_un.a_st.a,这是不太需要的。

这是必要的邪恶还是我在这里错过了什么?

提前致谢

【问题讨论】:

  • struct c { union ab; } 你没有收到警告吗?
  • @Jean-ClaudeArbaut - 从stackoverflow.com/questions/1972003/… 选择的答案有效,谢谢!
  • 仅供参考,C 2018 标准在 6.7.2.1 13 中指定匿名成员。它说匿名成员由“没有标签的结构说明符”或“没有标签的联合说明符”指定。换句话说,union ab; 没有指定匿名成员;它有一个标签,是union ab 类型的重新声明(由于其他原因,它具有未定义的行为)。因此,每个 6.7.2.1 13 的匿名工会成员必须具有 union { member declarations here }; 的形式。 (由于union ab; 声明具有标准未定义的行为,因此可以将其用于扩展,如答案中所述。)

标签: c struct union


【解决方案1】:

根据this answer,gcc 的解决方案是使用-fms-extensions 编译。

这是一个例子。使用 Visual C++ 和 MSYS2 gcc 10.2 测试。 使用这个版本的 gcc,-fms-extensions 似乎是隐含的,如果我用-fno-ms-extensions 编译而不是编译,我会收到 cmets 中提到的错误。

#include <stdio.h>

union ab {
    struct {
        int a;
    } a_st;
    struct {
        int b;
    } b_st;
};

typedef struct d {
    union ab;
    struct {
        int c;
    } c_st;
    
} d_st;

int main(void) {
    d_st x;
    printf("%zu\n", sizeof(d_st));
    x.a_st.a = 1;
    x.b_st.b = 2;
    x.c_st.c = 3;
    printf("a_st = %d\n", x.a_st.a);
    printf("b_st = %d\n", x.b_st.b);
    printf("c_st = %d\n", x.c_st.c);
    return 0;
}

【讨论】:

  • 谢谢,很有趣。我正在使用 gcc 8.4.0。这可能是这个 gcc 版本的错误吗?
  • @KamilCuk 等待,标签还是标识符?
  • 只是混乱。 C标准很明确C11 6.7.2.1p13An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure。它必须是未命名的并且没有标签。 struct ab; 没有名称(没有标识符),它有一个标签 - ab。 gcc 文档和 microsoft 文档似乎使用未命名/匿名同义词。
  • @TomDov 完成。实际上,它也解释了为什么它对我有用:与我所相信的相反,我使用 MSYS2 的 gcc 测试(即在 Windows 上)产生了很大的不同,因为选项 -fms-extensions 始终默认打开。
【解决方案2】:

作为扩展 MSVC 编译器(参见Microsoft Specific Anonymous Structures)和带有-fms-extensions 的gcc 编译器(参见gcc docs unnamed fields)支持未命名结构的语法。使用此扩展时,它允许代码编译和访问未命名的结构成员,就好像它们是包含结构的成员一样。

如果使用这个扩展,代码将编译并且访问是好的,你只是打错了c_st应该是d_st

#include <stdio.h>
union ab {
    struct {
        int a;
    } a_st;
    struct {
        int b;
    } b_st;
};
typedef struct d {
    union ab;
} d_st;
int main(void) {
    d_st c;
    printf("%d\n", c.a_st.a);
}

如果不使用此扩展,代码将无法编译,如下所述。


这是必要的邪恶还是我在这里错过了什么?

我会说这只是邪恶的。问题出在以下部分:

struct c {
   union ab;
};

和写一样:

struct c {
};

您可以输入任何类型并在其后添加;,例如:

struct d {
   int; float; unsigned long long; FILE *; some_other_type;
};

union ab 只是一个类型。 some_type ; 没有声明任何东西,没有任何反应。语言语法只允许您将类型编写为没有标识符的表达式(即,它用于像void func(char*, int) 这样的函数声明中),但没有任何反应,这样的表达式没有意义。你的struct c 是空的,它没有成员it's undefined behavior

试图直接“到达”联合元素:

您无法访问它们,因为它们不存在。 struct c 中没有元素 - 它是空的。

您可以复制代码(可能使用宏):

struct c {
    union {            // anonymous union
        struct {
            int a;
        } a_st;
        struct {
            int b;
        } b_st;
    };
};

并通过以下方式访问:

struct c C;
printf("%d\n", C.a_st.a);

【讨论】:

猜你喜欢
  • 2012-11-02
  • 1970-01-01
  • 2022-01-06
  • 2019-06-01
  • 2018-07-11
  • 2013-02-14
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多