C 是否有理由避免使用位字段结构成员?

C 是否有理由避免使用位字段结构成员?,c,struct,c99,bit-fields,principles,C,Struct,C99,Bit Fields,Principles,我早就知道C中有位字段,偶尔我会用它们来定义密集结构: typedef struct Message_s { unsigned int flag : 1; unsigned int channel : 4; unsigned int signal : 11; } Message; 当我阅读开源代码时,我通常会在手动滚动的位字段中找到位掩码和位移位操作来存储和检索这些信息。这是如此普遍,以至于我不认为作者不知道位字段语法,所以我想知道是否有理由通过位掩码和自己的移位

我早就知道C中有位字段,偶尔我会用它们来定义密集结构:

typedef struct Message_s {
     unsigned int flag : 1;
     unsigned int channel : 4;
     unsigned int signal : 11;
} Message;
当我阅读开源代码时,我通常会在手动滚动的位字段中找到位掩码和位移位操作来存储和检索这些信息。这是如此普遍,以至于我不认为作者不知道位字段语法,所以我想知道是否有理由通过位掩码和自己的移位操作来滚动位字段,而不是依赖编译器生成代码来获取和设置这些位字段

是否有理由避免使用位字段结构

位域结构有一些限制:

  • 位字段导致不可移植代码。此外,位字段长度对字大小有很高的依赖性
  • 由于不可寻址,无法读取(使用scanf())和在位字段上使用指针
  • 位字段用于将更多变量打包到更小的数据空间中,但会导致编译器生成额外的代码来操作这些变量。这导致了空间和时间复杂性的增加
  • sizeof()
    运算符不能应用于位字段,因为
    sizeof()
    以字节而不是位为单位生成结果
  • 所以你是否应该使用它们取决于。阅读更多


    附言:

    为什么其他程序员使用手工编码的位操作而不是位字段来将多个字段打包到一个单词中

    这个答案是基于意见的,因为这个问题相当开放:

    • 许多程序员不知道位字段的可用性,或者不确定它们的可移植性和精确语义。有些人甚至不相信编译器生成正确代码的能力。他们更喜欢编写他们理解的显式代码

      正如Cornstales所评论的,这种态度植根于现实生活经验

    • 位域的实际内存布局由实现定义:如果内存布局必须遵循精确的规范,则不应使用位域,可能需要手动编码位操作

    • 有符号类型位字段中有符号值的处理由实现定义。如果将有符号的值压缩到一系列位中,则手工编写访问函数可能更可靠


      • 没有理由这样做。位字段非常有用和方便。它们在嵌入式项目中有着广泛的应用。有些体系结构(如ARM)甚至有专门的指令来操作位字段

        只需比较代码(并编写函数foo1的其余部分)

        在许多情况下,能够寻址一个字内的单个位组或将一个字作为一个单元进行操作是很有用的。该标准目前没有提供 实现此类功能的任何实用且可移植的方法。如果代码是使用位字段编写的,并且以后有必要作为一个字访问多个组,那么如果不使用位字段重新编写所有代码,或者禁用基于类型的别名优化,使用类型双关,并希望一切都按预期安排,那么就没有好的方法来适应这种情况


        使用移位和掩码可能不美观,但直到C提供了将一个左值内显式指定的位序列视为另一个左值的方法,这通常是确保代码能够适应需要的最佳方法。

        这里可能已经考虑到了这一点:使用3
        无符号
        来存储
        16
        位——这些位都可以保存在1
        无符号
        中,例如
        结构{unsigned flag:1,channel:4,signal:11;}信息
        (注意字段定义后面使用的是
        ,“
        而不是
        ”;“
        )@DavidC.Rankin:3位字段占16位,很好地压缩成一个短单词。是的,你是正确的。因此,无论您是用一个字段声明3
        unsigned
        ,还是一个
        unsigned
        和3个字段,编译器只考虑在解析结构的
        sizeof
        时实际使用的字节。在过去的几天/几周里,您做了很多很好的工作——争取了50K?这里有更多的答案,而这些都是选择是否使用位域的相关注释,他们没有解决OP的问题,即为什么其他程序员使用手工编码的位操作而不是位字段来将多个字段打包成一个单词。@chqrlie您是说位字段的缺点并不是程序员选择避免位字段的原因?很明显,它们一定是这样。我是说,如果它们编写显式代码来访问打包到单词中的值,它们已经有了您列举的所有缺点,并且没有位字段的优点,这些优点使用起来更简单,更不容易出错。还有其他一些原因需要手工编码位操作,而不是像我在回答中引用的那样定义位字段。好吧,点#1是一个合理的原因,为什么手动按位操作可能是首选的。第2-4点适用于这两种情况,并不能回答这个问题。@Leushenko:endianness、单词大小和对齐方式会影响位级结构的布局。位字段增加了另一种实现定义行为,因为精确的位布局是独立于endianness实现定义的。“有些人甚至不相信编译器生成正确代码的能力。”。或者不确定它们的可移植性和精确语义=>好吧,考虑到你的最后两点,我们很难指责他们,因为有这么多实现定义的行为:(@Cornstalks Yea-差不多6年前的文章。太好了。@Cornstalks:读起来很有趣。谢谢你的指针。在访问后续位字段时读写
        volatile
        字段时,肯定会出现编译器错误。我会附上你的评论。如果有语法说结构