Therefore, convert the values before operating on them:
u1 = ((uint64_t) bf.uf1) << 20;
u2 = ((uint64_t) bf.uf2) << 20;> 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.
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?
That is to say, if we work this example with bitfields that are 8 bits wide, like
uint32_t uf2 : 8;
bf.uf2 = 255;
and use a shift of 24: u2 = bf.uf2 << 24;
the behavior observed on GCC will not change if we edit the declaration of the member to unsigned char: unsigned char uf2;
I.e. an unsigned bitfield that is 8 bits wide is basically like unsigned char and promotes that way. From that the reasoning follows for other widths.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.
If you assume that int is 32 bits, you can left shift an 12 bit field by 19 bits without hitting the sign bit.