Packing Bits ?

Started by
11 comments, last by Endemoniada 20 years, 1 month ago
Hi guys, I learn best from example so would someone please show me how to do this: I want a 2-byte (short) to store 2 single byte values like this: BYTE left; BYTE right; unsigned short combo = the combined bits; combo looks like this afterwards (with bits sets of course): | 00000000 | 00000000 | left right I guess I can figure out how to get them out if I know how to get them in. I think I have to use the left-shift << operator but I need an example. I looked at the RGB macro in VC++ and can''t figure out how it works. I really want to do this on longs that are 32 bits each. Any help is appreciated.
Advertisement
Is this right ?

BYTE left;
BYTE right;
unsigned short combo;

combo=left;
combo <<= 8;
combo |= right;

Can I make it better ?
unsigned char byte1;
unsigned char byte2;
unsigned short pack;

This will put byte1 in the low 8 bits and byte2 in the high 8 bits. It shifts byte2 to the left 8 bits, making it 8 bits higher and making room for byte1. I'm ashamed to say it, but I'm not sure if the typecast is necessary or not. I see above you used an OR to combine the final result. That works exactly the same as an addition in this case, so either will work.
pack = ((unsigned short)byte2 << 8) + byte1;

This will take byte1 from the low 8 bits of the pack. & is the bitwise AND symbol. It allows you to select which bits to keep and which to make zero. 0xff is the hexadecimal number for the binary number, 0000000011111111. Note that the high 8 bits are off (they get zeroed) and the low 8 bits are on (they are kept).
byte1 = pack & 0xff;

This will take byte2 from the high 8 bits of the pack. It shifts the 16 bit pack to the right 8 bits. The low 8 bits are pushed off the edge and lost to oblivion and the high 8 bits become the low 8 bits. Then, the 16 bit short is implicitly cast to an 8 bit byte, knocking off the (now zeroed) high 8 bits.
byte2 = pack >> 8;

[edited by - dcosborn on February 29, 2004 7:11:47 PM]
Should do the trick. Only works with two-byte shorts, though, but that''s generally not a problem...

cya,
Drag0n


-----------------------------
"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning..." -- Rich Cook
-----------------------------"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning..." -- Rich Cook"...nobody ever accused English pronounciation and spelling of being logical." -- Bjarne Stroustrup"...the war on terror is going badly because, if you where to compare it to WWII, it's like America being attacked by Japan, and responding by invading Brazil." -- Michalson
That helps a lot dcosborn.

I was wondering why some examples I saw used hex and now I know. If I know the bits I want what''s the best way to get a hex number ? For example, I needed a bits configuration with a starting 1 then all zeroes so I went like this:

unsigned long c=1;
c <<= 31;

I guess I can do the binary math then use sprintf to convert to hex because I can''t do hex on paper that well. I''m learning encryption so this binary and hex stuff is kinda new to me.
or you can try without shifting

struct short_st
{
short int hi:8;
short int low:8;
};

short_st var;

var.hi = 4;
var.low = 3;

www.autodefrost.com/~travisSignature Virus cleaned by McAfee
For converting binary to decimal: Each bit has a value that can be expressed with this function: f(n)=2^n (n is the bit number, lowest bit is 0). Simply add up the values of each ON bit.

Ex: 00110101 = 1+4+16+32 = 29

To convert binary to hex: Each hex digit contains 4 bits giving it a range of 0-F. Just add up the value of each 4 bit segment, in the same way as above, per hex digit. After awhile, you'll remember the patterns and you'll be able to convert 4 bits of binary to a hex digit without thinking.

Ex: 11011100 = 13,12 = 0xD,0xC = 0xDC

A couple helpful conversions:
If you only want the highest bit set, it would be 0x8000 for a 16-bit short. If you want everything except the highest bit set, it would be 0x7fff.

Edit: Clarification

[edited by - dcosborn on February 29, 2004 10:12:24 PM]
union short_split {    short S;    struct {        char hi;        char lo;    } b;} myVar;myVar.S = 32790;myVar.b.hi = myVar.b.lo;


BE FORWARNED! This code segment is only correct for big-endian processors! The x86 line is little-endian! Switch the order of "hi" and "lo" for little-endian processors!

Also keep in mind that on Microsoft compilers, which support anonymous structures, having an instance of the struct is entirely optional. You can omit the "b" at the end of the struct decl., and you can skip the ".b" portion when referencing members of it. Anonymous unions are part of the C(99?) standard, but anonymous structures are not.

(anonymous unions or structures work by exposing their members to their parent scopes; to create one, simply do not give the union/struct either a typename or a list of instances)

Against TCPA!
I am a signature virus. Please add me to your signature so that I may multiply.
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
After giving the OP another stare, I''ve noticed the last bit that was not phrased as a question; "I''d like to do this with 32-bit longs too".

Well, you know the math. You have chars (8 bits) or shorts (16 bits) or ints (usually 32 bits on current common platforms) or longs (usually 32 or 64 bits on current common platforms).

If you want to replace the highest word of a long with the value of a char, you push those 8 bits 24 places over, so they overlap with bits 31 through 24 of the long. And you want to keep the original bits 23 through 0 of that long, so mask off the high byte and add the shifted char to the current low three.

char c0, c1, c2, c3;long L;L = (L & 0x00FFFFFF) + (c3 << 24); 

Easy as cake, I hope. Each two hex digits represents one byte, FF represents the binary bits 11111111 (8 1''s), and you seem like you know how bitwise arithmetic works.

Just ask if you''re still having trouble!
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
Hi guys, I''ve been studying and now understand this stuff. Is this the tightest I can get ? I broke it up into 2 unsigned shorts because it seemed like it would be better than four unsigned long casts but I really don''t know. (I read something strange about efficiency I''ll post in a minute.)

BYTE b1=100;
BYTE b2=1;
BYTE b3=200;
BYTE b4=2;

unsigned long combo;

// put the bits in
combo=(unsigned long)(((unsigned short)b1 << 8 | b2) << 16) | ((unsigned short)b3 << 8 | b4);

// do some stuff here

// get the bits out
BYTE mask=0xff;

b4=(BYTE)combo & mask;
b3=(BYTE)(combo >>= 8) & mask;
b2=(BYTE)(combo >>= 8) & mask;
b1=(BYTE)(combo >>= 8) & mask;

I have to do the above operations a lot so I want to make it as best as I can.

Also, now I really understand what happens when you do a cast, I never really understood that until now :o)

Thanks for all the help guys.

This topic is closed to new replies.

Advertisement