This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

sizeof of struct with bit Field

please explain me why the sizeof (C51) returns 6 bytes for this struct instead of 5:

typedef struct DEKO_COMM_HEADER
{ UINT16 m_uiMsgOpcode;
UCHAR8 m_sblMsgPriority :2;
UINT16 m_sblDataLength :11;
UINT16 m_sblMsgTimeStamp :11;
}DEKO_COMM_HEADER, *PDEKO_COMM_HEADER;

UINT16 is typedef for unsigned int
UCHAR8 is typedef for unsigned char

thanks

Parents
  • Strictly speaking, per C89, a bitfield always occupies an "int". Despite the signed-ness of that declaration, the actual value of the bitfield may be signed or unsigned. (That is, an implementation may sign-extend a bitfield when it's used in comparisons, passed as a parameter, and so on. The "1" you assigned to a 1-bit bitfield might turn into a -1.) It's up to the implementation what order bitfields are allocated in those ints, and whether it uses bits MSB-to-LSB or vice versa.

    (In fact, bitfields are pretty much non-portable and implementation-dependent. Add in the fact that most compilers generate worse code for bitfield access than when you use mask-and-shift operations, and I generally just recommend against using them at all.)

    Though it's not standard, every compiler I've ever used allows you to specify a type other than "int" to hold bitfields. Usually, this is to conserve space.

    Note that in your example you shift types from U8 to U16. This is almost certainly guaranteed to prevent the compiler from putting the bitfields in the same struct member, as it can do when the types remain the same.

    C compilers are not allowed to reorder fields in a structure. They must occur in memory in the order of declaration. (C++ compilers are allowed to reorder structs unless they're declared 'extern "C"', but I've never met a compiler that actually does so.)

    So:

    U8 :2 // two bits come out of the first byte
    U16 :11 // can't fit in the U8, move on to the next int
    U16 : 11 // can't fit in the previous U16, use another

    I'd expect this structure to occupy 7 bytes.

Reply
  • Strictly speaking, per C89, a bitfield always occupies an "int". Despite the signed-ness of that declaration, the actual value of the bitfield may be signed or unsigned. (That is, an implementation may sign-extend a bitfield when it's used in comparisons, passed as a parameter, and so on. The "1" you assigned to a 1-bit bitfield might turn into a -1.) It's up to the implementation what order bitfields are allocated in those ints, and whether it uses bits MSB-to-LSB or vice versa.

    (In fact, bitfields are pretty much non-portable and implementation-dependent. Add in the fact that most compilers generate worse code for bitfield access than when you use mask-and-shift operations, and I generally just recommend against using them at all.)

    Though it's not standard, every compiler I've ever used allows you to specify a type other than "int" to hold bitfields. Usually, this is to conserve space.

    Note that in your example you shift types from U8 to U16. This is almost certainly guaranteed to prevent the compiler from putting the bitfields in the same struct member, as it can do when the types remain the same.

    C compilers are not allowed to reorder fields in a structure. They must occur in memory in the order of declaration. (C++ compilers are allowed to reorder structs unless they're declared 'extern "C"', but I've never met a compiler that actually does so.)

    So:

    U8 :2 // two bits come out of the first byte
    U16 :11 // can't fit in the U8, move on to the next int
    U16 : 11 // can't fit in the previous U16, use another

    I'd expect this structure to occupy 7 bytes.

Children
No data