Are there reasons to avoid bit-field structure members?
Asked Answered
B

4

23

I long knew there are bit-fields in C and occasionally I use them for defining densely packed structs:

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

When I read open source code, I instead often find bit-masks and bit-shifting operations to store and retrieve such information in hand-rolled bit-fields. This is so common that I do not think the authors were not aware of the bit-field syntax, so I wonder if there are reasons to roll bit-fields via bit-masks and shifting operations your own instead of relying on the compiler to generate code for getting and setting such bit-fields.

Backstairs answered 3/9, 2017 at 8:56 Comment(7)
This has probably already been considered here: #2638515Cythera
You are somewhat defeating the purpose using 3 unsigned to store 16 bits -- that can all be held in 1 unsigned, e.g. struct { unsigned flag : 1, channel : 4, signal : 11; } Message; (note the use of ',' not ';' following the field definitions)Vilmavim
@DavidC.Rankin: the 3 bit-fields account for 16 bits, nicely packed into a single short word.Questioning
Yes, you are correct. So regardless of whether you declared 3 unsigned with one-field each, or one, unsigned and 3-fields, the compiler just considers the bytes actually used when resolving the sizeof the struct..You have been doing a lot of good work these past couple of days/weeks -- pushing for 50K?Vilmavim
More answers here Why bit endianness is an issue in bitfieldsShipowner
@DavidC.Rankin: I must admit SO is a tad addictive. I should do some Javascript or Python to get rep faster, but C is definitely my favorite topic ;-)Questioning
@DavidC.Rankin There is no semantic difference between the struct defined in the question, and your suggestion of stating "unsigned" once. It is the same as declaring 3 variables of the same type on a single line, or on separate lines; it makes no difference, other than declaring them separately is (subjectively speaking, admittedly) clearer.Network
Q
17

Why other programmers use hand-coded bit manipulations instead of bitfields to pack multiple fields into a single word?

This answer is opinion based as the question is quite open:

  • Many programmers are unaware of the availability of bitfields or unsure about their portability and precise semantics. Some even distrust the compiler's ability to produce correct code. They prefer to write explicit code that they understand.

    As commented by Cornstalks, this attitude is rooted in real life experience as explained in this article.

  • Bitfield's actual memory layout is implementation defined: if the memory layout must follow a precise specification, bitfields should not be used and hand-coded bit manipulations may be required.

  • The handing of signed values in signed typed bitfields is implementation defined. If signed values are packed into a range of bits, it may be more reliable to hand-code the access functions.

Questioning answered 3/9, 2017 at 9:13 Comment(5)
"Some even distrust the compiler's ability to produce correct code." And sometimes with good reason.Nog
or unsure about their portability and precise semantics => well, given your last 2 points, one can hardly fault them seeing as there's so much implementation defined behavior :(Fiance
@Nog Yea - almost 6 years old article. Great.Employ
@Cornstalks: very interesting read. Thanks for the pointer. Definitely a compiler bug IMHO in the case of the volatile field being read and written when accessing the subsequent bitfield. I shall include your remark.Questioning
"Bitfield's actual memory layout is implementation defined" <- is this solely due to byte order issues (i.e. little-endian vs big-endian) or is there something else?Murmuration
A
8

Are there reasons to avoid bitfield-structs?

bitfield-structs come with some limitations:

  1. Bit fields result in non-portable code. Also, the bit field length has a high dependency on word size.
  2. Reading (using scanf()) and using pointers on bit fields is not possible due to non-addressability.
  3. Bit fields are used to pack more variables into a smaller data space, but cause the compiler to generate additional code to manipulate these variables. This results in an increase in both space as well as time complexities.
  4. The sizeof() operator cannot be applied to the bit fields, since sizeof() yields the result in bytes and not in bits.

Source

So whether you should use them or not depends. Read more in Why bit endianness is an issue in bitfields?


PS: When to use bit-fields in C?

Audun answered 3/9, 2017 at 9:4 Comment(8)
While these are all pertinent remarks for chosing to use bitfields or not, they do not address the OP's question as to why other programmers use hand-coded bit manipulations instead of bitfields to pack multiple fields into a single word.Questioning
@Questioning You're saying the drawbacks of bitfields are not reasons why programmers might choose to avoid bitfields? It seems obvious that they must be.Valor
I'm saying that if they write explicit code to access values packed into a word, they already have all the drawbacks that you enumerate and none of the advantages of bitfields which are much simpler to use and much less error-prone. There are other reasons to hand-code bit manipulations instead of defining bitfields as I quoted in my answer.Questioning
Well, point #1 is a valid reason why manual bitwise operations might be preferred. Points 2-4 apply to both and do not answer the question.Peltast
Bit fields do not result in non-portable code. Any portability issues you're likely to encounter are because you're doing something more complicated (assuming the endianness or size of binary data? aliasing something?) that is going to be just as non-portable without the use of bitfields.Wayless
@Leushenko: endianness, word size and alignment affect the layout of structures at the bit level. bit-fields add another level of implementation defined behavior as the precise bitwise layout is implementation defined independently of endianness.Questioning
@Leushenko Uh, what? Bit fields absolutely do result in non-portable code. Suppose you're reading a binary file format from disk. The file format specification says that the least-significant bit of byte 0 has some meaning. With bitwise operations, you can extract that bit portably with byte & 1. You can't do that with bit-fields because you have no guarantee how the bit fields are packed and ordered.Peltast
@Peltast No, that's not an issue related to bit-fields. That's exactly an example of implementation-defined issue caused by assuming the layout of external data and trying to alias it through a type that doesn't support the concept you're asking for ("least/most significant bit" is an arithmetic concept in C that has no relation to memory layout, and that's why bitfields can't specify this. To access bits based on this property, you should be using an arithmetic type in the first place, not a struct).Wayless
E
4

There is no reason for it. Bitfields are useful and convenient. They are in the common use in the embedded projects. Some architectures (like ARM) have even special instructions to manipulate bitfields.

Just compare the code (and write the rest of the function foo1) https://godbolt.org/g/72b3vY

Employ answered 3/9, 2017 at 10:20 Comment(3)
If there were a syntax to say that a structure should e.g. contain a uint32_t foo, but also allow a programmer to attach names to particular combinations of bits within foo, that would make bit fields very useful and portable while adding very little complexity to compilers. Unfortunately, most of the situations I've found where any kind of bitfields would be useful would require having control over the layout--something the Standard has not provided.Auriga
It is well defined for the particular compiler. I see it from perspective as I am mostly the bare metal coder. Potability is not the most important issue.Employ
@supercat: I agree completely, this is so frustrating!. It would be so useful to have a precise subset of Standard C with such details are fully defined and many cases of undefined or implementation defined behavior solved with the commonly expected semantics.Questioning
A
0

In many cases, it is useful to be able to address individual groups of bits within a word, or to operate on a word as a unit. The Standard presently does not provide any practical and portable way to achieve such functionality. If code is written to use bitfields and it later becomes necessary to access multiple groups as a word, there would be no nice way to accommodate that without reworking all the code using the bit fields or disabling type-based aliasing optimizations, using type punning, and hoping everything gets laid out as expected.

Using shifts and masks may be inelegant, but until C provides a means of treating an explicitly-designated sequence of bits within one lvalue as another lvalue, it is often the best way to ensure that code will be adaptable to meet needs.

Auriga answered 4/9, 2017 at 17:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.