Hacker news

  • Top
  • New
  • Past
  • Ask
  • Show
  • Jobs

C Bit-Field Pitfalls (https://www.os2museum.com)

30 points by fanf2 3 days ago | 8 comments | View on ycombinator

kazinator 3 days ago |

You're supposed to know that bitfields undergo promotion as they were small integers, even if they are declared to be something like unsigned int.

Therefore, convert the values before operating on them:

    u1 = ((uint64_t) bf.uf1) << 20;
    u2 = ((uint64_t) bf.uf2) << 20;

pjmlp 3 days ago |

It is much safer to pack/unpack bits manually than trusting bitfields will work as expected.

wahern 3 days ago |

It's even more confusing than described. C23 6.7.3.1p7 says,

> Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier `int` designates the same type as `signed int` or the same type as `unsigned int`.

That means a bit-field member using plain `int` as the underlying type might itself be signed or unsigned, similar to whether plain `char` is signed or unsigned. There's a proposal to address this: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3828.pdf Fortunately, it found that GCC, Clang, MSVC, and ICC all treat `int` bit-fields as `signed int`, and the recommendation is to require this behavior.

That said, I don't think I've ever seen a bit-field deliberately used for signed values; there's some logic to the allowance granted by the standard. And I'm sure there's plenty of real-world code erroneously using `int` bit-fields for unsigned values that just happens to work because of twos-complement representations and the semantics of bitwise operations. But better to limit this kind of flexibility, especially when real-world implementations seem not to have taken the alternative route.

mwkaufma 3 days ago |

tl;dr standard is unclear if they should respect the signed-ness of the declaration (MSCV), or always promote to int before converting to a receiving type (GCC, Clang).

I suppose you could say MS's choice reflects a commitment to backwards compatibility, whereas GCC/Clang is always chomping at the bit to introduce more aggressive optimizations that signed-integer-undefined-behavior affords?

fsckboy 3 days ago |

>The troublesome behavior is demonstrated by the lines performing the left shift. We take a 12-bit wide bit-field, shift it left by 20 bits so ...

this is nonsense. I don't know what they expect would happen, but who cares? I wouldn't shift a 12 bit field by more than ±11 bits.

you can shift the "enclosing" word of memory if you want, just put the original definition in a union.