在C中的未命名联合中达到命名结构

Posted

技术标签:

【中文标题】在C中的未命名联合中达到命名结构【英文标题】:Reaching named struct in Unnamed union in 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,这是不太需要的。

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

提前致谢

【问题讨论】:

***.com/questions/3228104/… ***.com/questions/13624760/…, ***.com/questions/1972003/… struct c union ab; 你没有收到警告吗? @Jean-ClaudeArbaut - 从***.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; 声明具有标准未定义的行为,因此可以将其用于扩展,如答案中所述。) 【参考方案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;

【讨论】:

奇怪,I get a lot of errors. 谢谢,很有趣。我正在使用 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);

【讨论】:

union ab; 不是什么,它是无名联合。 gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields If -fms-extensions is used, the field may also be a definition with a tag such as 这是重要的部分。

以上是关于在C中的未命名联合中达到命名结构的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的匿名结构体

C语言中的匿名结构体

重命名 Pyspark Dataframe 中的未命名列

重命名 bigquery 标准 SQL 中的未命名列

访问 Ajax 对象中的未命名值

C中的“结构命名空间”有技术原因吗?