Sign in to follow this  
masterviking

3 byte numbers!? [in C++]

Recommended Posts

masterviking    100
I got no idea if there exists 3 byte numbers.. I just know of short int (2 bytes) & int (4 bytes) Please don't say:"Use an int!", because im making a network app that needs to send alot of 3 byte numbers. If there exists none (i have googeled), then is it possible to construct one? It must work with all C++ operations... There should exist.. I hope :)

Share this post


Link to post
Share on other sites
dave    2187
Well number of bytes that a built in type takes up is platform dependant. But typically no there isnt one. The only solid solution i can think of is to write a class that manages 3 chars, overloads all the operators so that it can be added to things etc etc

Dave

Share this post


Link to post
Share on other sites
joanusdmentia    1060
Quote:
Original post by masterviking
Please don't say:"Use an int!", because im making a network app that needs to send alot of 3 byte numbers.


And the problem with using an int (assuming a 32-bit int) to store the value and only transmitting the 3 lower bytes is.....what?

Share this post


Link to post
Share on other sites
Dtag    210
You can work with an unsigned int like this:


void Encode(unsigned int a, char* pDest)
{
memcpy(pDest,&a,3);
}

unsigned int Decode(const char* pSrc)
{
unsigned int ret=0;
memcpy(&ret,pSrc,3);
return ret;
}





But be aware that this will only work on little endian systems, where data is stored like this AABBCCDD where AA is the least significant byte. In that case the memcpy will take the first 3 bytes and copy them to the char buffer dropping the DD. So if you need something platform independant, you need to code seperate versions for both endianesses.

Share this post


Link to post
Share on other sites
__ODIN__    479
Presumably he's attempting to save 1 bytes by sending 3 byte positions or 3 byte IDs instead of going all out for a 4 byte integer.

There's no standard type that uses 3 bytes, though you could probably build on as a class, and override +,/,-,= etc to make it look like an intrinsic. I'm not certain it's a good idea; you might be better of just taking the hit for the 4 byte system, rather than taking a hit on conversion in and out (not to mention all the fun overflow errors you're opening yourself to).

Very often, the higher-level optimizations (deciding WHAT to send) is more important than the lower-level optimization (cut 8 bits from that number). You might get as good (or better) performance by running the packet through a compression algorithm as part of your packet-sender (either a simple huffman, or a more complex, zlib like, compression).

Allan

Share this post


Link to post
Share on other sites
nmi    978
Quote:
Original post by C0D1F1ED
Try using bitfields like this:
*** Source Snippet Removed ***


This won't work, since the basic type is int.

To create a 3 byte number, it is possible to create an overloaded class which stores three bytes (characters) internally. Since a characters size and alignment is 1, this will make a struct containing three of them have a size of 3 and an aligment of 1.

Share this post


Link to post
Share on other sites
starmole    126
Use an int. Period. But use a method that does not write the uppermost byte
into the data stream if necessary. But use an int for any local computations. Otherwise you gain a byte on the network for a slow computation on both ends. Unless your network is a 1200 baud modem from the 80s, there is no rationale
for doing this.

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by starmole
Use an int. Period. But use a method that does not write the uppermost byte
into the data stream if necessary. But use an int for any local computations. Otherwise you gain a byte on the network for a slow computation on both ends. Unless your network is a 1200 baud modem from the 80s, there is no rationale
for doing this.
Seconded.

If you have a lot of 3-byte numbers in a struct, then you could use a bitfield like C0D1F1ED suggested, but that'll still be rounded up to the nearest sizeof(int) bytes. The main benifit is that if you have a number that ranges from 0-10, then you only need 4 bits to represent it, and you can pack 2 of those into 1 byte.

Share this post


Link to post
Share on other sites
masterviking    100
Thank you all for the answers!

This sounds perfect:
"
void Encode(unsigned int a, char* pDest)
{
memcpy(pDest,&a,3);
}

unsigned int Decode(const char* pSrc)
{
unsigned int ret=0;
memcpy(&ret,pSrc,3);
return ret;
}
"
!!!! thanx!

"And the problem with using an int (assuming a 32-bit int) to store the value and only transmitting the 3 lower bytes is.....what?"
Because I want to send a structure that contains 3 byte numbers + others.
& now that will work with the encoding techniqe.

+ Thank you for learning me bitfields! It will be very useful!
One can now define real bits now! that's nice :D (you know... the bool have the size of 1byte)

Share this post


Link to post
Share on other sites
joanusdmentia    1060
Quote:
Original post by masterviking
"And the problem with using an int (assuming a 32-bit int) to store the value and only transmitting the 3 lower bytes is.....what?"
Because I want to send a structure that contains 3 byte numbers + others.
& now that will work with the encoding techniqe.


For that to work you have to make sure you turn off packing with #pragma pack(1). For example, the following would be an 8-byte if the #pragma lines weren't included despite the fact that you only declare 7 bytes, padding would be inserted between value1 and value2 to place value2 on a 4-byte boundary:


#pragma pack(1,push)

struct NetworkPacket
{
char value1[3];
int value2;
};

#pragma pack(pop)




Secondly, sending an entire struct as a network packet is a bad idea as it forces you to have machines with the same endianness on both ends of the connection. Assuming you're using this struct solely for network transfers you have to copy the data into it before the transfer member by member, and then you have to touch on the data again to send it. Instead you could serialize the data member by member without any extra work (per packet, you'll still need some sort of serialization system, boost::serialize might help here) AND you get the benefit of being able to convert your data to network endianness (thus making it endianness independant).

Share this post


Link to post
Share on other sites
masterviking    100
Thank you for that inspiration joanusdmentia!
But why whould it insert padding?

Edit:
While learning about endianness on wiki I found:
#define LITTLE_ENDIAN 0
#define BIG_ENDIAN 1

int machineEndianness()
{
int i = 1;
char *p = (char *) &i;
if (p[0] == 1) // Lowest address contains the least significant byte
return LITTLE_ENDIAN;
else
return BIG_ENDIAN;
}
Nice, huh? :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
There articles may be of interest for you:
Packing Integers
Developing Your Own Replay System (also deals with bit-packing)
There is also an interesting article in Game Programming Gems 4 called "Bit Packing: A Network Compression Technique."

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Ok. So hyperlinks don't work.
http://number-none.com/product/Packing%20Integers/index.html (Packing Integers)
http://www.gamasutra.com/features/20040204/wagner_pfv.htm (Developing Your Own Replay System)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this