结构体中的隐藏成员(Gcc)

3

目前,我正在使用嵌入式设备进行工作。

我正在创建自己的“寄存器表示法”,以学习C语言中的过程。

我通过在给定位置放置结构体来实现这一点:

struct myIo {
   u32 flagA : 1;
   u32 fieldB : 7;
   u32 reserved : 24;
   u32 regB;
};

struct __attribute__((section("sec"))) myIo MyIo;

这个代码可以正常工作,但是我想知道如何移除

reserved

字段不会影响硬件所执行的填充/对齐方式。

我的问题是:

如何设计一个结构体,使得其中的“隐藏”字段在访问结构体时不会显示出来。

本质上:

MyStruct.reserved = val;

或者

val = MyStruct.reserved;

应该抛出编译错误和类型错误

MyIo.

在Eclipse CDT C/C++中,不应该出现“自动完成”选项。

我正在使用Arm Cross GCC和Eclipse CDT C/C++。

我熟悉符合C标准的解决方案、编译器pragma解决方案和预处理器解决方案。


只需删除 reserved — 除非你打算对结构体进行打包(不建议这样做!),否则 regB 将会被正确地对齐。或者,将 reserved 替换为 u32 : 0;,以强制对齐到下一个存储单元。 - Jonathan Leffler
@JonathanLeffler 为什么不打包这个结构?你能解释一下吗? - ElectronicsStudent
如果你打包结构体,RegB 的对齐就不能再保证了(在位域中任何事情都不是完全保证的——它们非常“实现定义”)。如果你有显式的 reserved 成员,或者有一个匿名的 24 位位域,那么你就没问题了。但是去掉位域并打包结构体会让编译器能够在名称后面的 8 位保留字节之后立即对齐 RegB - Jonathan Leffler
@JonathanLeffler 感谢您的澄清。您提到,位域由于实现定义行为而容易引起问题。您能否解释一下这是什么意思? - ElectronicsStudent
标准规定的位域规则非常灵活,许多属性是实现定义的。因此,编写使用位域的可移植代码很困难。您需要仔细隔离位域定义,以便适应实际使用的实现。请参阅C11 §6.7.2.1 结构和联合说明符 以了解大部分肮脏的细节 - 但也包括§3.14§6.2.6。注意:理论上,u32可能无效... - Jonathan Leffler
1个回答

5
你可以创建一个未命名的位域:
struct myIo {
   u32 flagA : 1;
   u32 fieldB : 7;
   u32 : 24;
   u32 regB;
};

根据C标准第6.7.2.1p12节关于“结构和联合说明符”的规定,这样的构造是允许的:

没有声明符,只有一个冒号和一个宽度的位域声明表示一个无名位域。126)特殊情况下,宽度为0的位域结构成员表示不再在之前的位域所占用的单元中打包其他位域。


126 ) 一个无名位域结构成员可用于填充以符合外部强制的布局要求。

请注意,在这种情况下,零大小的位域也可以工作,但是只能因为后面没有其他位域。


u32 : 0; 也可以工作。 - Jonathan Leffler
@dbush 感谢您,先生!您很快就解决了我的问题。 - ElectronicsStudent
你能否明确这是GCC特定还是标准C? - pm100
这是标准的 C 语言,@pm100。 - Jonathan Leffler

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