RPGDXThe center of Indie-RPG gaming
Not logged in. [log in] [register]
 
*SOLVED* packing 8bit data in 32bit variables
 
Post new topic Reply to topic  
View previous topic - View next topic  
Author Message
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Sun Feb 17, 2008 8:51 am    Post subject: *SOLVED* packing 8bit data in 32bit variables [quote]

*SOLVED*
The idea is to store 4 8bit unsigned char values in a single 32bit unsigned long integer variable.

I wrote up some code for packing and unpacking, which I think is correct but I'd really like someone to take a look at it and let me know if I'm doing it right or not.
Code:


typedef unsigned char  u8;  // 8-bits (a single byte)  0 to 255 decimal
typedef unsigned short u16; // 16-bit unsigned integer 0 to 65535 decimal.
typedef unsigned long  u32; // 32-bit unsigned integer 0 to 4294967295 decimal.

// pack two 8bit values in a 16bit variable
void U16_Packin(u8 a, u8 b, u16& store)
{
   store = ((u16)(((u8)(a)) | (((u16)((u8)(b))) << 8)));
}

// pack two 16bit values in a 32bit variable
void U32_Packin(u16 a, u16 b, u32& store)
{
   store = ((u32)(((u16)(a)) | (((u32)((u16)(b))) << 16)));
}

// unpack two 8bit values from a 16bit variable
void U16_Unpack(u16& packed, u8& storeA, u8& storeB)
{
   storeA = ((u8)(packed));
   storeB = ((u8)(((u16)(packed) >> 8) & 0xFF));
}

// unpack two 16bit values from a 32bit variable
void U32_Unpack(u32& packed, u16& storeA, u16& storeB)
{
   storeA = ((u16)((u32)(packed)));
   storeB = ((u16)(((u32)(packed) >> 16) & 0xFFFF));
}


My test below yields the wrong results when I unpack the data. :(
Code:

void CreateMapEvent(u8 id, u8* params, u32& store)
{
   u16 packetA, packetB;
   U16_Packin(id, params[0], packetA);
   U16_Packin(params[1], params[2], packetB);
   U32_Packin(packetA, packetB, store);
}

char* GetEventType(u32& evnt)
{
   if (evnt)
   {
      u16 packet, junk;
      U32_Unpack(evnt, packet, junk);
      u8 id, junk2;
      U16_Unpack(packet, id, junk2);
      switch(id)
      {
      case 128:
         {
            return "Map Warp";
         } break;
      default:
         return "Unknown Event Type";
      }
   }
   return "No Event";
}

char get_event_parameter_storage[256];
char* GetEventParameter(u32& evnt, int index)
{
   if (evnt)
   {
      u16 packetA, packetB;
      U32_Unpack(evnt, packetA, packetB);
      u8 param1, param2, param3, junk;
      U16_Unpack(packetA, junk, param1);
      U16_Unpack(packetB, param2, param3);
      ChrMapChar params[] = {param1, param2, param3};
      index -= 1;
      index = index % 3;
      sprintf_s(get_event_parameter_storage,256, "%d", params[index]);
      return get_event_parameter_storage;
   }
   return "?";
}

// this test code is called in my main()
u32 testEvent = 0;
u8 warpID = 128, x = 24, y = 17;
u8 params[] = {x, y, 0};
CreateMapEvent(warpID, params, testEvent);

engine->GetScreen()->Printf(2, 2, "Event        : %d", testEvent);
engine->GetScreen()->Printf(2, 4, "Event Type   : %s", GetEventType(testEvent));
engine->GetScreen()->Printf(2, 6, "Event Param 1: %s", GetEventParameter(testEvent, 1));
engine->GetScreen()->Printf(2, 8, "Event Param 2: %s", GetEventParameter(testEvent, 2));


the results I get:
Quote:

Event : 16717952
Event Type : Map Warp
Event Param 1: 24
Event Param 2: 255

I have no idea why I'm not getting the 17 for Y...its baffling me.
Any help would be greatly appreciated.
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio


Last edited by DeveloperX on Sun Feb 17, 2008 9:23 am; edited 2 times in total
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Sun Feb 17, 2008 8:58 am    Post subject: [quote]

disregard that. I found a stray line of code that was from old code that I forgot to remove. testEvent |= 0x00FF0000;

HAHAHA. sorry, foolish me. :D But at least it works now.
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
RedSlash
Mage


Joined: 12 May 2005
Posts: 331

PostPosted: Sun Feb 17, 2008 8:39 pm    Post subject: [quote]

I'm surprised you didn't try a structure based approach.
Code:

struct MapEvent
{
   u8 type;
   u8 param[3];
};

struct MapEvent e;

e.type = 128;
e.param[0] = x;
e.param[1] = y;
e.param[2] = 0;

u32 packed_int = *(u32 *)&e; // <- gives you your 32-bit int

The above is compiler/OS dependant. I would find this an easier solution.
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Mon Feb 18, 2008 9:45 pm    Post subject: [quote]

I guess I'm a glutton for punishment. :P
Well, my code works for my purposes, so no point in changing it. :)
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
Rainer Deyke
Demon Hunter


Joined: 05 Jun 2002
Posts: 672

PostPosted: Tue Feb 19, 2008 6:05 am    Post subject: [quote]

Actually casting (pointers to) structs to (pointers to) integers is endian-dependent behavior, which is generally bad thing. DeveloperX's code will produce consistent results across compilers, OSs, and CPU architectures.
Back to top  
RedSlash
Mage


Joined: 12 May 2005
Posts: 331

PostPosted: Wed Feb 20, 2008 1:21 am    Post subject: [quote]

Which is why I mentioned that my solution was compiler/OS dependant. I therefore propose this change to make it more portable across platforms:
Quote:

u32 packed_int = e.type | (e.param[1] << 8) | (e.param[2] << 16) | (e.param[3] << 24);

DevX code isn't completely portable neither because he defined u32 as unsigned long, which is not a 32-bit int on 64-bit platforms. He is also using a non-standard C library function sprintf_s (MSVC).
Back to top  
oenone
Sick of Being A Fairy Princess Yet?


Joined: 17 Aug 2007
Posts: 14
Location: germany

PostPosted: Wed Feb 20, 2008 4:30 pm    Post subject: [quote]

RedSlash wrote:
unsigned long, which is not a 32-bit int on 64-bit platforms

That is compiler dependant. The C standard never defined how many bit which type has to have.

You can't say long is not 32-bit on 64-bit platforms, without telling us which compiler you mean.
Back to top  
RedSlash
Mage


Joined: 12 May 2005
Posts: 331

PostPosted: Wed Feb 20, 2008 4:50 pm    Post subject: [quote]

Ops! yes you are correct. I guess what I meant to mean is that we shouldn't depend on C datatypes for sizes if we're going for cross-platform.
Back to top  
Rainer Deyke
Demon Hunter


Joined: 05 Jun 2002
Posts: 672

PostPosted: Wed Feb 20, 2008 6:59 pm    Post subject: [quote]

I use this:
Code:
#include "boost/cstdint.hpp"
boost::uint32_t x;

Also valid would be this:
Code:
#include <cstdint>
std::uint32_t x;

Or, in C:
Code:
#include <stdint>
uint32_t x;


(Edit: stdint.h in C. Stupid message board keeps stripping out the .h)
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Wed Feb 20, 2008 9:18 pm    Post subject: [quote]

its good to see I've stirred up some discussion around here :)

I'm not aiming for portability really, as this was really just meant for my map engine, and perhaps I'll use it for other things, but as for other architectures & compilers? nah.

my final setup is a two file (a habit of mine) setup:

DataUtility.h
Code:

#ifndef DATAUTILITY_H
#define DATAUTILITY_H

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;

class DataUtility
{
public:
   static void U16_Packin(u8 a, u8 b, u16& store);
   static void U32_Packin(u16 a, u16 b, u32& store);
   static void U16_Unpack(u16& packed, u8& storeA, u8& storeB);
   static void U32_Unpack(u32& packed, u16& storeA, u16& storeB);
private:
   DataUtility();
};

#endif


DataUtility.cpp
Code:


#include "DataUtility.h"

void DataUtility::U16_Packin(u8 a, u8 b, u16& store)
{
   store = ((u16)(((u8)(a)) | (((u16)((u8)(b))) << 8)));
}

void DataUtility::U32_Packin(u16 a, u16 b, u32& store)
{
   store = ((u32)(((u16)(a)) | (((u32)((u16)(b))) << 16)));
}

void DataUtility::U16_Unpack(u16& packed, u8& storeA, u8& storeB)
{
   storeA = ((u8)(packed));
   storeB = ((u8)(((u16)(packed) >> 8) & 0xFF));
}

void DataUtility::U32_Unpack(u32& packed, u16& storeA, u16& storeB)
{
   storeA = ((u16)((u32)(packed)));
   storeB = ((u16)(((u32)(packed) >> 16) & 0xFFFF));
}


I stripped out the large amount of comments that I have in these files to cut down on the 'spamming' on the forums. :)

Using it is simple (to me) an excerpt from my MapEvent.cpp file:
Code:

#include "DataUtility.h"

void MapEvent::Create(u8 eventType, u8* parameters, u32& store)
{
   u16 packetA;
   u16 packetB;

   DataUtility::U16_Packin(eventType, parameters[0], packetA);
   DataUtility::U16_Packin(parameters[1], parameters[2], packetB);
   DataUtility::U32_Packin(packetA, packetB, store);
}

_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
valderman
Mage


Joined: 29 Aug 2002
Posts: 334
Location: Gothenburg, Sweden

PostPosted: Tue Apr 22, 2008 10:59 am    Post subject: [quote]

Sorry for resurrecting this old thread, but is there any reason why you can't just use a union instead?

Code:
typedef union {
    unsigned char u8[4];
    unsigned long u32;
} u8x4_t;


Much more readable, and I believe the compiler might generate faster code with it too (avoiding the multiple function calls (for cases where they can't be inlined,) two shifts and two and/ors, emitting instead a single add.)
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Tue Apr 22, 2008 1:00 pm    Post subject: [quote]

Never thought of using a union.
Eh oh well. That project isn't going anywhere anytime soon anyway. Its sitting in the far corner of my dev folder.
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
Post new topic Reply to topic Page 1 of 1 All times are GMT
 



Display posts from previous:   
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum