Formatting Unions inside bitfields in C

user6025958

I have a particular problem in which I have a 16 bit structure. Inside the structure, after the member "x_pos", depending on some external flag, the next 5 bits represent something different.

If the external flag is set, they are rotation & scaling parameters (rotscale_param), else the upper two bits are horizontal and vertical flip bits.

I've tried to represent this structure using a union, but when I so sizeof(attribute), I'm expecting to see 2 bytes, but the result is 4 bytes.

My Code:

typedef unsigned short u16;

struct attribute {
    u16 x_pos : 9;
    union {
        u16 rotscale_param : 5;
        struct {
            u16 unused : 3;
            u16 hflip : 1;
            u16 vflip : 1;
            };
    };
    u16 size : 2;
};

If it helps, I'm trying to make C code for this structure:

OBJ Attribute 
  Bit   Expl.
  0-8   X-Coordinate           
  When Rotation/Scaling used:
    9-13  Rotation/Scaling Parameter Selection
  When Rotation/Scaling not used:
    9-11  Not used
    12    Horizontal Flip      
    13    Vertical Flip        
  14-15 OBJ Size

Source of above quote : http://problemkaputt.de/gbatek.htm#lcdobjoamattributes

Here is a potential solution:

typedef struct attr_flag_set {
    u16 x_pos : 9;
    u16 rotscale_param : 5;
    u16 size : 2;
};

typedef struct attr_flag_unset {
    u16 x_pos : 9;
    u16 unused : 3;
    u16 hflip : 1;
    u16 vflip : 1;
    u16 size : 2;
};

union attribute_1 {
    attr_flag_unset attr_unset;
    attr_flag_set attr_set;
};

I'm not sure if this is the ideal solution, however.

Frankie_C

It's not easy to get the correct packing.
Moreover the standard allows bits packing only while the declarations are of the same type.
From ISO/IEC 9899 C99, 6.7.2.1 Structure and union specifiers:

An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

So when you insert a bitfield struct inside a bitfield declaration this breaks the rules and reserves another WORD for storage.
The only workaround is to revert the declaration to a union of 2 different structures:

#pragma pack(1)
union attribute
{
    struct
    {
        u16 x_pos : 9;    //See the homogeneous series of declarations
        u16 rotscale_param : 5;
        u16 size : 2;
    } struct1;
    struct
    {
        u16 x_pos  : 9;    //See the homogeneous series of declarations here also
        u16 unused : 3;
        u16 hflip  : 1;
        u16 vflip  : 1;
        u16 size   : 2;
    } struct2;
};

This works for me under C99-C11.
Don't forget to instruct compiler to pack data. As Mah makes me note this can be accomplished with pragma on most compilers or with a specific syntax on others. And also in this case the packing can be compiler dependent on those border line applications.
P.S. Consider also that bytes order is compiler dependent, but substantially depend on CPU endianess, and for this reason a code that works well on a little-endian machine may fail on a big-endian one.
The best practice would be to use masks and shifts if a fully portable code is desired.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

TOP Ranking

HotTag

Archive