I have a struct
as follows.
struct A {
uint32_t a : 1;
uint32_t b : 1;
};
Is struct A
guaranteed by the standard to have size 4? Is it possible that a compiler instead
uses only one byte for struct A
since it uses exactly two bits?
struct B {
uint32_t a : 1;
uint32_t b : 1;
uint32_t c : 30;
} b;
If I would like to set the bitfields in b
to zero, since sizeof(struct B) = 4
, it looks good to me to do so by
*(uint32_t*)&b = 0
. But I saw a lot of discussions on SO arguing that such a pointer cast is a bad practice. I wonder what makes *(uint32_t*)&b = 0
bad here and what I should do (I know I can use memset
to reset the bitfields but I am interested in other portable ways).
CodePudding user response:
Is
struct A
guaranteed by the standard to have size 4?
No. It might be size 4, might not.
Is it possible that a compiler instead uses only one byte for struct A since it uses exactly two bits?
Yes, it is possible.
I wonder what makes
*(uint32_t*)&b = 0
bad here ...
- Code may assign outside
b
(undefined behavior (UB)). - Assignment may be insufficient to zero out
b
. - Rare: the optional type
uint32_t
may not exist. - Code risks aliasing issues.
... and what I should do
To zero out b
, assign a struct B
that is zero. Research compound literal. Notice this code below applies to various types, not just struct
with bit-fields.
b = (struct B){0};
Or maybe, if you desire a non-zero value:
b = (struct B){.a = 0, .c = 42, .b = 1};
Bit fields are tricky. Use signed int
, unsigned int
and _Bool
and not uint32_t
for maximum portability.
A bit-field shall have a type that is a qualified or unqualified version of
_Bool
,signed int
,unsigned int
, or some other implementation-defined type. It is implementation-defined whether atomic types are permitted. C17dr § 6.7.2.1 5
CodePudding user response:
The first question, you can add an alignment, but this will affect the execution efficiency:
#pragma pack(push)
#pragma pack(1)
struct A {
uint32_t a : 1;
uint32_t b : 1;
};
#pragma pack(pop)
The second question, you can define it as union
union B {
struct {
uint32_t a : 1;
uint32_t b : 1;
uint32_t c : 30;
};
uint32_t u;
} b;
// set the bitfields in b to zero
b.u = 0;