21

我早就知道 C 中有位域,有时我用它们来定义密集的结构:

typedef struct Message_s {
     unsigned int flag : 1;
     unsigned int channel : 4;
     unsigned int signal : 11;
} Message;

当我阅读开源代码时,我经常会找到位掩码和位移操作来在手动位字段中存储和检索此类信息。这很常见,我认为作者不知道位域语法,所以我想知道是否有理由通过位掩码和移位操作来滚动位域,而不是依赖编译器生成获取和设置此类位域的代码。

4

4 回答 4

16

为什么其他程序员使用手动编码的位操作而不是位域来将多个域打包成一个单词?

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

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

    正如 Cornstalks 所评论的那样,这种态度植根于本文所述的现实生活经验。

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

  • 有符号类型位域中有符号值的处理是实现定义的。如果有符号值被打包到一个位范围内,则手动编码访问函数可能更可靠。

于 2017-09-03T09:13:55.450 回答
8

是否有理由避免使用位域结构?

位域结构有一些限制:

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

资源

所以你是否应该使用它们取决于。在为什么位字节序是位域中的一个问题中阅读更多内容?


PS:什么时候在 C 中使用位域?

于 2017-09-03T09:04:15.567 回答
4

没有理由这样做。位域非常有用且方便。它们在嵌入式项目中很常见。一些体系结构(如 ARM)甚至具有操作位域的特殊指令。

只需比较代码(并编写函数 foo1 的其余部分) https://godbolt.org/g/72b3vY

于 2017-09-03T10:20:36.537 回答
0

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

使用移位和掩码可能不太优雅,但在 C 提供一种将一个左值内明确指定的位序列视为另一个左值的方法之前,它通常是确保代码能够适应需求的最佳方法。

于 2017-09-04T17:53:20.377 回答