Menu

#3530 sizeof() struct with bitfields is incorrect

closed-rejected
None
Front-end
5
2022-12-15
2022-12-15
Jeff Trull
No

The following code produces a 2B struct in gcc and a 3B struct in sdcc:

#include <stdint.h>

typedef struct bitfields
{
    uint16_t field0 : 1;
    uint16_t field1 : 1;
    uint16_t unused : 14;
} bitfields;

static const uint8_t bitfields_size = sizeof(bitfields);  // 2 in gcc, 3 in sdcc
static const uint8_t u16_size = sizeof(uint16_t);         // 2 in both

Command used: sdcc -c mre.c
sdcc version: 4.2.0
Expected: bitfields_size should be 2
Observed: bitfields_size is 3

Discussion

  • Philipp Klaus Krause

    • status: open --> closed-rejected
    • assigned_to: Philipp Klaus Krause
    • Category: other --> Front-end
     
  • Philipp Klaus Krause

    This is implementatin-defined behaviour (see e.g. section .7.2.1 in the C2X draft N3074). What SDCC does is a valid choice and documented (section 3.1.7.9 in the SDCC manual).

    P.S.: While GCC apparently uses two bytes on the system where you tried it, the behaviour of GCC actually depends on the target.

    P.P.S.: A more efficient struct layout would be to have the 14-bit field first, followed by the two 1-bit fields. In that case (assuming bytes are 8 bit for the target, which is true for all SDCC targets), the C standard mandates that all members fit into 2 bytes.

     
  • Erik Petrich

    Erik Petrich - 2022-12-15

    The sizeof operator is working correctly in sdcc; if allocated, struct bitfields would occupy 3 bytes of memory. (field0 and field1 in the first byte, and unused in the second and third). While the minimum size of the struct could be 2 bytes, the C standard leaves much of the handling of bitfields to be implementation defined. Part of sdcc's implementation is "if a bit-fields does not fit into the same byte as the previous bit-fields, it starts on the next byte."

    Since a 14-bit bitfield will not fit into the 6 bits remaining of the first byte, sdcc realigns it to the start of the next byte. If you need sdcc to create a 2-byte struct, you could change your declaration to either:

    typedef struct bitfields1
    {
        uint16_t unused : 14;
        uint16_t field0 : 1;
        uint16_t field1 : 1;
    } bitfields1;
    
    typedef struct bitfields2
    {
        uint16_t field0 : 1;
        uint16_t field1 : 1;
        uint16_t unused0 : 6;
        uint16_t unused1 : 8;
    } bitfields2;
    
     
  • Jeff Trull

    Jeff Trull - 2022-12-15

    Thank you, I did not know this could be implementation-defined! I will file an issue with the upstream source code, along with the workaround you suggested.

     

Log in to post a comment.