在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中的未命名联合中达到命名结构的主要内容,如果未能解决你的问题,请参考以下文章