arrayscstructbit-fieldssdcc

How to create packed arrays of bit fields with SDCC?


I have a nested data structure containing arrays of bit fields which I need to compile with SDCC for the MCS-51 target.

This is a simplified example:

example.c

struct data {
    unsigned char a : 1;
    unsigned char b : 2;
};

struct data dummy[8];

void main()
{
}

Since struct data contains 3 bits, 8 instances contain 24 bits in total, so 3 bytes of memory would be sufficient to store them.

But SDCC allocates 8 bytes, as we can see in the resulting example.asm:

$ sdcc -c example.c
$ cat example.asm
[…]
; File Created by SDCC : free open source ANSI-C Compiler
; Version 3.5.0 #9253 (Mar 19 2016) (Linux)
[…]
        .module example
        .optsdcc -mmcs51 --model-small
[…]
        .area DSEG    (DATA)
_dummy::
        .ds 8

Is there a way to get SDCC to allocate only 3 bytes for dummy?

As a workaround I am currently not using a struct at all, but instead use some macros for calculating the total size of the data structure, allocating a flat array of bytes, and generating the indices and bit masks for accessing the individual members. I would like to use syntax like dummy[5].b instead.

Some compilers seem to have options to enable packing of bit fields (like #pragma pack), but I did not find anything like that in the SDCC manual.


Solution

  • It is not possible in any compiler I afraid. It will allocate at least one byte for every struct

    I would do something like this:

    typedef struct {
        unsigned char a0 : 1;
        unsigned char b0 : 2;
        unsigned char a1 : 1;
        unsigned char b1 : 2;
        unsigned char a2 : 1;
        unsigned char b2 : 2;
        unsigned char a3 : 1;
        unsigned char b3 : 2;
        unsigned char a4 : 1;
        unsigned char b4 : 2;
        unsigned char a5 : 1;
        unsigned char b5 : 2;
        unsigned char a6 : 1;
        unsigned char b6 : 2;
        unsigned char a7 : 1;
        unsigned char b7 : 2;
    }data;
    
    data dx;
    
    #define GT(dt,member,bit)   ((dt).member ##bit)
    
    void foo()
    {
        GT(dx,b,5) = 2;
    }