Why is assigning a value to a bit field not giving the same value back?
Bit-fields are incredibly poorly defined by the standard. Given this code struct mystruct {int enabled:1;};
, then we don't know:
- How much space this occupies - if there are padding bits/bytes and where they are located in memory.
- Where the bit is located in memory. Not defined and also depends on endianess.
- Whether an
int:n
bitfield is to be regarded as signed or unsigned.
Regarding the last part, C17 6.7.2.1/10 says:
A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits 125)
Non-normative note explaining the above:
125) As specified in 6.7.2 above, if the actual type specifier used is
int
or a typedef-name defined asint
, then it is implementation-defined whether the bit-field is signed or unsigned.
In case the bitfield is to be regarded as signed int
and you make a bit of size 1
, then there is no room for data, only for the sign bit. This is the reason why your program might give weird results on some compilers.
Good practice:
- Never use bit-fields for any purpose.
- Avoid using signed
int
type for any form of bit manipulation.
I am unable to understand, how is it possible that we set something and then it doesn't show up as it is.
Are you asking why it compiles vs. gives you an error?
Yes, it should ideally give you an error. And it does, if you use your compiler's warnings. In GCC, with -Werror -Wall -pedantic
:
main.cpp: In function 'int main()':
main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
changes value from '1' to '-1' [-Werror=overflow]
s.enabled = 1;
^
The reasoning for why this is left up to being implementation-defined vs. an error may have more to do with historical usages, where requiring a cast would mean breaking old code. The authors of the standard may believe warnings were enough to pick up the slack for those concerned.
To throw in some prescriptivism, I'll echo @Lundin's statement: "Never use bit-fields for any purpose." If you have the kind of good reasons to get low-level and specific about your memory layout details that would get you to thinking you needed bitfields in the first place, the other associated requirements you almost certainly have will run up against their underspecification.
(TL;DR - If you're sophisticated enough to legitimately "need" bit-fields, they're not well-defined enough to serve you.)