14

我需要以这种方式将一些位打包成一个字节:

struct  
{  
  char bit0: 1;  
  char bit1: 1;  
} a;  

if( a.bit1 ) /* etc */

或者:

if( a & 0x2 ) /* etc */

从源代码的清晰度来看,对我来说很明显位域更整洁。但是哪个选项更快?我知道速度差异不会太大,但我可以使用它们中的任何一个,如果一个更快,更好。
另一方面,我读到位域不能保证跨平台以相同的顺序排列位,我希望我的代码是可移植的。

注意:如果您打算回答“个人资料”,我会的,但由于我很懒,如果有人已经有了答案,那就更好了。
代码可能是错误的,如果您愿意,可以纠正我,但请记住这个问题的意义,并请尝试回答。

4

7 回答 7

12

如果使用得当,位域会使代码更加清晰。我只会将位域用作节省空间的设备。我见过它们使用的一个常见地方是在编译器中:通常类型或符号信息由一堆真/假标志组成。位域在这里是理想的,因为一个典型的程序在编译时会创建成千上万个这样的节点。

我不会使用位域来完成常见的嵌入式编程工作:读取和写入设备寄存器。我更喜欢在这里使用移位和掩码,因为您可以获得文档告诉您需要的确切位,并且您不必担心位域的各种编译器实现的差异。

至于速度,一个好的编译器将为位域提供与掩码相同的代码。

于 2010-01-24T14:24:22.510 回答
7

我宁愿使用第二个示例来获得最大的可移植性。正如 Neil Butterworth 指出的那样,使用位域仅适用于本机处理器。好吧,想想这个,如果 Intel 的 x86 明天停业,代码会卡住,这意味着必须为另一个处理器重新实现位域,比如 RISC 芯片。

您必须放眼大局,询问 OpenBSD 是如何使用一个代码库将他们的 BSD 系统移植到许多平台的?好的,我承认这有点过分,有争议和主观,但实际上,如果你想将代码移植到另一个平台,这是使用你在问题中使用的第二个示例的方法.

不仅如此,不同平台的编译器将有自己的填充方式,为编译器所在的处理器对齐位域。此外,处理器的字节序又如何呢?

永远不要依赖位域作为灵丹妙药。如果您想要处理器的速度并将其固定在上面,即不打算移植,那么请随意使用位域。你不能两者兼得!

于 2010-01-24T14:54:26.407 回答
6

C 位域从发明的那一刻起就夭折了——原因不明。人们不喜欢它们,而是使用按位运算符。您必须期望其他开发人员不理解 C 位域代码。

关于哪个更快:无关紧要。任何优化编译器(实际上意味着所有)都会使代码以任何符号执行相同的操作。C 程序员的一个常见误解是编译器只会在汇编中搜索和替换关键字。现代编译器使用源代码作为应该实现的蓝图,然后生成通常看起来非常不同但达到预期结果的代码。

于 2010-01-24T14:48:28.893 回答
5

第一个是显式的,无论第二个表达式的速度如何,都容易出错,因为对结构的任何更改都可能使第二个表达式出错。

所以使用第一个。

于 2010-01-24T14:15:34.483 回答
4

如果您想要可移植性,请避免使用位域。如果您对特定代码的性能感兴趣,除了编写自己的测试之外别无选择。请记住,位域将在后台使用处理器的按位指令。

于 2010-01-24T14:14:46.370 回答
1

我认为 C 程序员会倾向于使用位掩码和逻辑运算来推断每个位的值的第二种选择。与其让代码中堆满十六进制值,不如设置枚举,或者,通常在涉及更复杂的操作时,使用宏来获取/设置特定位。我听说过,结构实现的位域速度较慢。

于 2010-01-24T14:15:23.450 回答
1

不要在“非便携式位域”中阅读太多内容。实现定义的位字段有两个方面:符号和布局,一个未指定的方面:打包它们的分配单元的对齐方式。如果您不需要任何其他包装效果,则使用它们与signed也具有未指定属性的函数调用一样可移植(前提是您在需要的地方明确指定关键字)。

关于性能,配置文件是您可以获得的最佳答案。在一个完美的世界里,这两个作品之间没有区别。在实践中,可能有一些原因,但我可以想到一个方向和另一个方向一样多的原因。它可能对上下文非常敏感(例如,无符号和有符号之间在逻辑上没有意义的差异)所以在上下文中测量......

总而言之,差异主要是在您真正有选择的情况下的风格差异(即,如果精确的布局很重要,则不是)。在这种情况下,它是一种优化(在大小上,而不是在速度上),所以我倾向于首先编写没有它的代码,然后在需要时添加它。因此,位字段是显而易见的选择(要进行的修改是实现结果的最小修改,并且包含在唯一的定义位置,而不是分散到所有使用位置)。

于 2010-01-24T15:57:24.103 回答