C/C++位域与逐位运算符相比,单位输出位更快,更好,更便携?

Pet*_*uza 13 c c++ bit-manipulation bit-fields

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

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

if( a.bit1 ) /* etc */
Run Code Online (Sandbox Code Playgroud)

要么:

if( a & 0x2 ) /* etc */
Run Code Online (Sandbox Code Playgroud)

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

注意:如果您打算回答"个人资料",我会,但是因为我很懒,如果有人已经有了答案,那就更好了.
代码可能有误,如果你愿意,可以纠正我,但请记住这个问题的重点是什么,请尝试回答.

Ric*_*ton 12

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

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

至于速度,一个好的编译器会给掩盖的位域提供相同的代码.

  • @Jalf:你错了.标准说"存储在位域中的值由m位组成,其中m是为位字段指定的大小." 实现不能忽略m. (2认同)

t0m*_*13b 7

我宁愿使用第二个例子而不是最大的可移植性.正如Neil Butterworth指出的那样,使用位域仅适用于原生处理器.好吧,想想看,如果英特尔的x86明天停业,会发生什么,代码将被卡住,这意味着必须为另一个处理器重新实现位域,RISC芯片说.

你必须从更大的角度来看看OpenBSD如何使用一个代码库将他们的BSD系统移植到很多平台?好吧,我承认这有点过头,有争议和主观,但实际上,如果你想将代码移植到另一个平台,它的方法是使用你在问题中使用的第二个例子.

不仅如此,不同平台的编译器将有自己的填充方式,为编译器所在的处理器对齐位域.而且,处理器的endianess怎么样?

永远不要依赖比特场作为魔术子弹.如果你想要处理器的速度并将固定在它上,即无意移植,那么随意使用位域.你不能两个都有!

  • 注意如何使用手动定义的内置位域更便携?我可以相信,如果你依赖于结构的内存布局是一种非常确定的方式,但如果你只是通过内置语法访问每个字段,我就看不到任何可移植性问题. (7认同)

Tho*_*n79 6

C bitfields从它们被发明的那一刻开始就是死产 - 原因不明.人们不喜欢它们而是使用按位运算符.您必须要求其他开发人员不理解C位域代码.

关于哪个更快:不相关.任何优化编译器(这几乎都意味着所有)将使代码以任何表示法执行相同的操作.这是C程序员的常见误解,编译器只会将关键字搜索和替换为汇编.现代编译器使用源代码作为应该实现的目标的蓝图,然后发出通常看起来非常不同但实现预期结果的代码.


小智 5

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

  • 还有包装问题。仅仅因为处理器有特殊用途的指令,就不能保证编译器会使用它 - 这就是为什么我说测试是必不可少的。 (3认同)
  • 啊,但是仅仅因为位域可能会根据实现使用更多或更少的空间,并不意味着它是不可移植的。如果编译器没有利用处理器的功能,则应该对其进行改进或替换。 (2认同)
  • 一些编译器可以识别位域操作并使用处理器的位域操作。我知道 GCC 是为 AVR 这样做的,以至于 AVRlibc 人们只提供在汇编中实现的位域函数作为对遗留代码的支持,并建议新代码使用 `REG |= 0x08;` 或 `REG &= ~ 0x08;`(例如)构造。这种编译器优化类似于编译器用位移位替换 2 的幂的整数乘法和除法。 (2认同)

Kla*_*aim 5

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

所以使用第一个.