See online example: Ideone example
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
Why would the compiler report the size of the struct as 5 bytes instead of 4 here? It should contain 32 bits.
The sizeof for a struct is not always equal to the sum of sizeof of each individual member. This is because of the padding added by the compiler to avoid alignment issues. Padding is only added when a structure member is followed by a member with a larger size or at the end of the structure.
The size is at least sizeof(int) + sizeof(struct node *) + sizeof(struct node *) . But it may be more as the compiler is allowed to add padding bytes to your structure if it wishes.
Above is the alignment of the structure A, and that's why the size of the struct is 32 Bytes. Also, the object a of type struct A is 32 Bytes.
The size of the entire structure is 8 bytes. On knowing the structured padding, it is easier to redesign or rewrite the structure.
The problem is that __attribute__((packed))
doesn't perform bitwise packing. It just guarantees that there is no padding between struct
members. You can try this simpler example, where size is also reported as 5:
typedef struct structTag {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
Bitwise packing is only possible for bitfield members. You will need to redesign your struct to be a union of a struct with bitfields messageID/priority/canFlags, and a struct with bitfields rowID/canFlags. In other words, you will need to either have some duplication or resort to accessor macros or member functions.
It's because of memory alignment: The compiler won't start canFlags
in the middle of a byte, it'll start it at the beginning of the next byte (probably*). So you have four bytes for your initial union, and a byte for canFlags
.
If, for instance, you moved canFlags
into the union, it would (probably*) have size 4:
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
uint32_t rawID : 29;
uint8_t canFlags : 3; /* <==== Moved */
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
Updated example on ideone. Obviously, that specific change probably isn't what you want; I'm just demonstrating that the issue is starting a new field not on a byte boundary.
* "probably" because ultimately it's up to the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With