大佬教程收集整理的这篇文章主要介绍了位字段的意外行为,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
#include <stdio.h> struct s { int a : 6; _Bool b : 1; _Bool c : 1; _Bool d : 1; _Bool e : 1; _Bool f : 1; _Bool g : 1; int h : 12; }; void main(void) { printf("%d\n",sizeof(struct s)); }
输出有点出乎意料.
12
如C11草案所述,
因为我使用了32位编译器,所以我预计它会适合4个字节.具体来说,我使用了gcc(tdm-1)5.1.0.这是违反标准的吗?
编辑:
将所有_Bools替换为int按预期工作…我不知道为什么……
编辑:
在gcc 5.4.0中,代码按预期工作.这个问题的关键点是为什么尾随的_Bools和int不适合第一个.我想我没有做太多关于实现的假设(除了int至少4个字节,这是可以接受的),我在这里谈论C标准的C保证行为.因此,我不能同意下面的一些评论.
首先,您引用的完整部分(6.7.2.1/11)说:
所有这一切都意味着你几乎不能对这些位如何在内存中结束做出任何假设.你不可能知道编译器将如何排列对齐,你不可能知道位的位顺序,你无法知道签名,你无法知道endianess.
至于if int和_Bool将合并到同一个“存储单元”……好吧,为什么会这样?它们是不兼容的类型. C标准没有提到当你有两个不相容类型的相邻位字段时会发生什么 – 它可以接受主观解释.我怀疑会有各种类型的别名问题.
因此,编译器完全可以将所有这些放在单独的“存储单元”中.如果您相邻地放置相同类型的项目,我会希望它合并它们或引用的部分没有任何意义.例如,我希望从以下大小8:
struct s { int a : 6; int h : 12; _Bool b : 1; _Bool c : 1; _Bool d : 1; _Bool e : 1; _Bool f : 1; _Bool g : 1; };
现在,如果你想要确定性的行为,你应该做什么,可移植代码是将位字段抛出窗口并使用逐位运算符.它们具有100%的确定性和便携性.
假设你实际上不想要一些神秘的签名号码字段,原始代码提示,那么:
#define a UINT32_C(0xFC000000) #define b (1u << 18) #define c (1u << 17) #define d (1u << 16) #define e (1u << 15) #define f (1u << 14) #define g (1u << 13) #define h UINT32_C(0x00000FFF) typedef uint32_t special_thing;
然后设计setter / getter函数或宏来设置/获取这个32位块的数据.写得正确,你甚至可以使这样的代码与endianess无关.
以上是大佬教程为你收集整理的位字段的意外行为全部内容,希望文章能够帮你解决位字段的意外行为所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。