gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Bitpacked unions

#119583 - LiraNuna - Sat Feb 24, 2007 2:03 pm

I usually never get anwers for my questions, but I'll give it a try anyway.

I'm writing an engine that heavily relays on bitbacked unions such as:

Code:
struct {
   u16 v1            :9;
   union {
      struct {
         u8 v2      :3;
         bool v3      :1;
         bool v4      :1;
      }; // 5bit
      u8 v5         :5;
   }; // 5bit union
   u8 v6            :2;
} name; // 16bit


However, when accessing variables inside the union, aren't "merging", and the size of the struct is 4, and not 2 as it should be.

Ofcourse, I tried this:


Code:
struct {
   u16 v1            :9;
   union {
      struct {
         u8 v2      :3;
         bool v3      :1;
         bool v4      :1;
      } PACKED; // 5bit
      u8 v5         :5;
   } PACKED; // 5bit union
   u8 v6            :2;
} PACKED name; // 16bit


But it didn't work too.

The only way I can get the struct to be sized '2' is to comment out the union:

Code:
struct {
   u16 v1            :9;
//   union {
//      struct {
         u8 v2      :3;
         bool v3      :1;
         bool v4      :1;
//      }; // 5bit
//      u8 v5         :5;
//   }; // 5bit union
   u8 v6            :2;
}; // 16bit


I don't want to use ugly tricks as "#define v5 v2" or similar. And I'm sure I'm misusing the union.
Any Ideas?
_________________
Private property.
Violators will be shot, survivors will be shot again.

#119584 - tepples - Sat Feb 24, 2007 2:12 pm

LiraNuna wrote:
I'm writing an engine that heavily relays on bitbacked unions

The order of objects within the integer represented by a bitfield is implementation defined. Therefore the behavior of a that contains such a bitfield is also implementation defined. Using explicit read-modify-write instructions is more likely to be portable should you ever want to port the engine to something other than a little-endian ARM CPU or a compiler other than GCC. In addition, a lot of compilers generate decidedly suboptimal code for bitfield manipulation.

Is there a specific reason that you're using bitfields instead of explicit RMW? I couldn't take a guess because you hid the variable names.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#119585 - LiraNuna - Sat Feb 24, 2007 2:15 pm

Yes there is a reason. And I know it's slower then normal |= and &= ~, but it should be bitpack.

I could tell you why, but that would just ruin the surprise :)
EDIT: The engine could not be portable.
_________________
Private property.
Violators will be shot, survivors will be shot again.

#119602 - DekuTree64 - Sat Feb 24, 2007 5:23 pm

I'm not positive, but I don't think bitfields work properly when you mix variable types like that. Try this:
Code:
struct {
   union {
      struct {
         u16 v1 : 9;
         u16 dummy : 7;
      };
      struct {
         u8 dummy2;  // Fill part of v1, since nothing overlaps it
         union {
            // Each of these overlap the upper 8 bits
            struct {
               u8 dummy3 : 1;
               u8 v2 : 3;
               u8 dummy4 : 4;
            };
            struct {
               bool dummy5 : 4;
               bool v3 : 1;
               bool v4 : 1;
               bool dummy6 : 2;
            };
            struct {
               u8 dummy7 : 1;
               u8 v5 : 5;
               u8 v6 : 2;
            };
         };
      };
   };
};

_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#119619 - LiraNuna - Sat Feb 24, 2007 8:41 pm

"Oh, I see what you did there..."
-- Kitten

I'll try it as soon as posible. But first, I'd like to post a 'refined' edition of yours, after understading the concept of your system:

Code:
typedef union {
   struct {
      u16 v1         :9;
      u8             :7;
   };
   struct {
      u8            :8;
      union {
         struct {
            u8      :1;
            u8 v2   :3;
            u8 v3   :1;
            u8 v4   :1;
            u8      :2;
         };
         struct {
            u8      :1;
            u8 v5   :5;
            u8 v6   :2;
         };
      };
   };
} name;


The idea of the 'unnamed' vars are standard C (99?) and fully legal.

Thanks a lot deku, I'll see if it works.

EDIT: works like a charm! Did I say thanks?
_________________
Private property.
Violators will be shot, survivors will be shot again.

#119770 - Lick - Mon Feb 26, 2007 12:55 am

I'm not really sure this is relevant or not, but I'll mention it anyway. Most of the time when I'm having problems with structs and the sizes of them, the following line before the struct declaration helps me get rid of them:

Code:

#pragma pack(1)
struct {...};


And AFAIK, it is only needed once, unless you change the value multiple times.
_________________
http://licklick.wordpress.com

#120320 - LiraNuna - Fri Mar 02, 2007 9:23 pm

If you'll read the post again, you'll see that PACKED (predefined) was my first attempt to solve the problem. of course it didn't change anything
_________________
Private property.
Violators will be shot, survivors will be shot again.