简体   繁体   English

C / C ++位域与按位运算符相比,可以更快,更好,更便携地选择位?

[英]C/C++ bitfields versus bitwise operators to single out bits, which is faster, better, more portable?

I need to pack some bits in a byte in this fashion: 我需要以这种方式在字节中打包一些位:

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

if( a.bit1 ) /* etc */

or: 要么:

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

From the source code clarity it's pretty obvious to me that bitfields are neater. 从源代码的清晰性来看,对我来说很明显位域更整洁。 But which option is faster? 但是哪个选择更快? I know the speed difference won't be too much if any, but as I can use any of them, if one's faster, better. 我知道速度差异不会太大,但是我可以使用其中的任何一个,如果速度更快,更好。
On the other hand, I've read that bitfields are not guaranteed to arrange bits in the same order across platforms, and I want my code to be portable. 另一方面,我读到不能保证位域在平台之间以相同顺序排列位,并且我希望代码具有可移植性。

Notes: If you plan to answer 'Profile' ok, I will, but as I'm lazy, if someone already has the answer, much better. 注意:如果您打算回答“个人资料”,可以,我会的,但是由于我很懒,如果有人已经有了答案,那就更好了。
The code may be wrong, you can correct me if you want, but remember what the point to this question is and please try and answer it too. 代码可能是错误的,如果需要,您可以纠正我,但请记住此问题的重点,也请尝试回答。

Bitfields make the code much clearer if they are used appropriately. 如果位域使用得当,它们会使代码更清晰。 I would use bitfields as a space saving device only. 我只会将位域用作节省空间的设备。 One common place I've seen them used is in compilers: Often type or symbol information consists of a bunch of true/false flags. 我见过它们使用的一个常见地方是在编译器中:类型或符号信息通常由一堆true / false标志组成。 Bitfields are ideal here since a typical program will have many thousands of these nodes created when it is compiled. 位域在这里是理想的,因为典型程序在编译时会创建成千上万个这样的节点。

I wouldn't use bitfields to do a common embedded programming job: reading and writing device registers. 我不会使用位域来完成常见的嵌入式编程工作:读取和写入设备寄存器。 I prefer using shifts and masks here because you get exactly the bits the documentation tells you you need and you don't have to worry about differences in various compilers implementation of bitfields. 我更喜欢在这里使用shift和mask,因为您可以准确地得到文档告诉您的所需位,而不必担心各种编译器在实现位域方面的差异。

As for speed, a good compiler will give the same code for bitfields that masking will. 至于速度,一个好的编译器将为位域提供与屏蔽相同的代码。

I would rather use the second example in preference for maximum portability. 为了获得最大的可移植性,我宁愿使用第二个示例。 As Neil Butterworth pointed out, using bitfields is only for the native processor. 正如尼尔·巴特沃思(Neil Butterworth)所指出的那样,仅对本机处理器使用位域。 Ok, think about this, what happens if Intel's x86 went out of business tomorrow, the code will be stuck, which means having to re-implement the bitfields for another processor, say RISC chip. 好了,想想看,如果英特尔的x86明天停产,代码将被卡住,这意味着必须重新实现另一个处理器的位域,如RISC芯片。

You have to look at the bigger picture and ask how did OpenBSD manage to port their BSD systems to a lot of platforms using one codebase? 您必须从更大的角度看,并问OpenBSD如何使用一个代码库将其BSD系统移植到许多平台上? Ok, I'll admit that is a bit over the top, and debatable and subjective, but realistically speaking, if you want to port the code to another platform, its the way to do it by using the second example you used in your question. 好的,我承认这有点过头了,值得商and和主观,但实际上,如果您要将代码移植到另一个平台,则可以使用问题中使用的第二个示例来实现。 。

Not alone that, compilers for different platforms would have their own way of padding, aligning bitfields for the processor where the compiler is on. 不仅如此,针对不同平台的编译器将具有自己的填充方式,将编译器所在的处理器的位字段对齐。 And furthermore, what about the endianess of the processor? 而且,处理器的耐久性如何?

Never rely on bitfields as a magic bullet. 永远不要把位域当作魔术子弹。 If you want speed for the processor and will be fixed on it, ie no intention of porting, then feel free to use bitfields. 如果您想要处理器的速度并将其固定在其上,即无意移植,则可以随意使用位域。 You cannot have both! 不能同时拥有!

C bitfields were stillborn from the moment they were invented - for unknown reason. 由于未知的原因,C位字段从被发明的那一刻就诞生了。 People didn't like them and used bitwise operators instead. 人们不喜欢它们,而是使用按位运算符。 You have to expect other developers to not understand C bitfield code. 您必须期望其他开发人员不了解C位域代码。

With regard to which is faster: Irrelevant. 关于哪个更快:不相关。 Any optimizing compiler (which means practically all) will make the code do the same thing in whatever notation. 任何优化的编译器(实际上是所有编译器)都会使代码以任何表示方式执行相同的操作。 It's a common misconception of C programmers that the compiler will just search-and-replace keywords into assembly. 对于C程序员来说,一个普遍的误解是编译器只是将关键字搜索并替换为汇编语言。 Modern compilers use the source code as a blueprint to what shall be achieved and then emit code that often looks very different but achieves the intended result. 现代编译器将源代码用作要实现的目标的蓝图,然后发出通常看起来非常不同但可以达到预期结果的代码。

The first one is explicit and whatever the speed the second expression is error-prone because any change to your struct might make the second expression wrong. 第一个是显式的,无论第二个表达式的速度如何,都容易出错,因为对结构的任何更改都可能使第二个表达式错误。

So use the first. 因此,请使用第一个。

If you want portability, avoid bitfields. 如果要携带,请避免使用位域。 And if you are interested in performance of specific code, there is no alternative to writing your own tests. 而且,如果您对特定代码的性能感兴趣,那么除了编写自己的测试之外别无选择。 Remember, bitfields will be using the processor's bitwise instructions under the hood. 记住,位域将在后台使用处理器的按位指令。

I think a C programmer would tend toward the second option of using bit masks and logic operations to deduce the value of each bit. 我认为C程序员倾向于使用位掩码和逻辑运算来推断每个位的值的第二种选择。 Rather than having the code littered with hex values, enumerations would be set up, or, usually when more complex operations are involved, macros to get/set specific bits. 可以使用枚举来设置枚举,或者通常在涉及更复杂的操作时使用宏来获取/设置特定位,而不是用十六进制值来填充代码。 I've heard on the grapevine, that struct implemented bitfields are slower. 我听说过,实现结构的位域速度较慢。

Don't read to much in the "non portable bit-fields". 在“非便携式位域”中不要读太多。 There are two aspects of bit fields which are implementation defined: the signedness and the layout and one unspecified one: the alignment of the allocation unit in which they are packed. 位域有两个方面,它们是实现定义的:有符号性和布局,一个未指定的域:打包它们的分配单元的对齐方式。 If you don't need anything else that the packing effect, using them is as portable (provided you specify explicitly a signed keyword where needed) as function calls which also have unspecified properties. 如果您不需要打包效果,使用它们就像函数调用一样具有可移植性(只要您在需要的地方明确指定一个带signed关键字),这些函数也具有未指定的属性。

Concerning the performance, profile is the best answer you can get. 关于性能,配置文件是您可以获得的最佳答案。 In a perfect world, there would be no difference between the two writings. 在一个完美的世界中,这两种著作之间没有区别。 In practice, there can be some, but I can think of as many reasons in one direction as the other. 实际上,可以有一些原因,但是我可以想到一个方向上与另一个方向上一样多的原因。 And it can be very sensitive to context (logically meaningless difference between unsigned and signed for instance) so measure in context... 而且它可能对上下文非常敏感(例如,无符号和有符号之间在逻辑上无意义的差异),因此请在上下文中进行测量...

To sum up, the difference is thus mostly a style difference in cases where you have truly the choice (ie not if the precise layout is important). 综上所述,因此,在您真正有选择权的情况下,差异主要是样式差异(即,如果精确的布局很重要则不是)。 In those case, it is a optimization (in size, not in speed) and so I'd tend first to write the code without it and add it after if needed. 在那种情况下,这是一种优化(大小,而不是速度),因此我倾向于先编写没有代码的代码,然后在需要时添加它。 So, bit fields are the obvious choice (the modifications to be done are the smallest one to achieve the result and are contained to the unique place of definition instead of being spread of to all the places of use). 因此,位字段是显而易见的选择(要做的修改是获得结果的最小修改,并且包含在定义的唯一位置,而不是扩展到所有使用位置)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM