22

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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
wirrbel
  • 3,173
  • 3
  • 26
  • 49
  • This has probably already been considered here: https://stackoverflow.com/questions/2638015/how-slow-are-bit-fields-in-c – yacc Sep 03 '17 at 09:07
  • 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) – David C. Rankin Sep 03 '17 at 09:20
  • 1
    @DavidC.Rankin: the 3 bit-fields account for 16 bits, nicely packed into a single short word. – chqrlie Sep 03 '17 at 09:25
  • 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? – David C. Rankin Sep 03 '17 at 09:41
  • 1
    More answers here [Why bit endianness is an issue in bitfields](https://stackoverflow.com/questions/6043483/why-bit-endianness-is-an-issue-in-bitfields) – Bo Persson Sep 03 '17 at 13:13
  • @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 ;-) – chqrlie Sep 03 '17 at 20:52
  • @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. – cosimo193 Dec 14 '22 at 22:28

4 Answers4

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.

Community
  • 1
  • 1
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 5
    *"Some even distrust the compiler's ability to produce correct code."* [And sometimes with good reason](https://lwn.net/Articles/478657/). – Cornstalks Sep 03 '17 at 14:39
  • *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 :( – Matthieu M. Sep 03 '17 at 17:07
  • @Cornstalks Yea - almost 6 years old article. Great. – 0___________ Sep 03 '17 at 18:46
  • @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. – chqrlie Sep 03 '17 at 20:22
  • "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? – einpoklum Jul 30 '21 at 13:25
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?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 7
    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. – chqrlie Sep 03 '17 at 09:07
  • 3
    @chqrlie You're saying the drawbacks of bitfields are not reasons why programmers might choose to avoid bitfields? It seems obvious that they must be. –  Sep 03 '17 at 09:10
  • 2
    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. – chqrlie Sep 03 '17 at 09:16
  • 3
    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. – jamesdlin Sep 03 '17 at 09:32
  • 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. – Alex Celeste Sep 03 '17 at 19:33
  • 2
    @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. – chqrlie Sep 03 '17 at 20:15
  • 1
    @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. – jamesdlin Sep 04 '17 at 10:02
  • @jamesdlin 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). – Alex Celeste Sep 04 '17 at 10:16
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

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 2
    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. – supercat Sep 03 '17 at 18:46
  • 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. – 0___________ Sep 03 '17 at 19:54
  • 1
    @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. – chqrlie Sep 03 '17 at 20:32
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.

supercat
  • 77,689
  • 9
  • 166
  • 211