|
|
View previous topic - View next topic |
Author |
Message |
DeveloperX 202192397
Joined: 04 May 2003 Posts: 1626 Location: Decatur, IL, USA
|
Posted: 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
|
Posted: 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
|
Posted: 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
|
|
Back to top |
|
|
Rainer Deyke Demon Hunter
Joined: 05 Jun 2002 Posts: 672
|
Posted: 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
|
Posted: 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
|
Posted: 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
|
Posted: 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
|
Posted: 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
|
Posted: 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
|
Posted: 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
|
Posted: 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 |
|
|
|
Page 1 of 1 |
All times are GMT
|
|
|
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
|
|