🔒 Locked
Packing bits into bytes.
Advertisement
Original Post
Hi folks. I'm wondering if you could help me with a problem I'm having. I'm fiddling around with some GBA programming and I'm having problems with packing bits into bytes. I need to do the following: I have an 8-bit number which has a 4-bit number (0..15) packed into it. I need to extract these 4-bit numbers and then pack 2 of them into an 8-bit unsigned char. If anyone could help out with a handy macro or function, I'd love you forever. This bit manipulation stuff is doing my head in! Thanks P.S. Would this be done differently on Big Endian and Little endian processors?
Quote:What does that mean? Does it have two 4-bit numbers packed into it, or is it just no more than 4 bits used? We need some clarification.
Original post by Arkasian
I have an 8-bit number which has a 4-bit number (0..15) packed into it.
Quote:Yes, it would.
P.S. Would this be done differently on Big Endian and Little endian processors?
Assuming you are using C or C++ you could do like this:
This should work.
[Edited by - CTar on October 26, 2005 10:43:58 AM]
unsigned char Pack(unsigned char LowPart,unsigned char HighPart){ // Use 15 (1111 in binary) to ensure the part isn't higher // than 15. // Use << 4 to move all bits 4 places to the side return (LowPart&15) + ((HighPart&15)<<4);}unsigned char ExtractLowPart(unsigned char PackedChar){ // Extract lower 4 bits return (PackedChar&15);}unsigned char ExtractHighPart(unsigned char PackedChar){ // Extract the 4 high bits return (PackedChar>>4);}This should work.
[Edited by - CTar on October 26, 2005 10:43:58 AM]
You could always use bitfields, assuming c/c++ again:
The one problem I have with this method is making sure that the compiler gives me the right size data structure (hence the assert), sometimes they tend to pad structures out to 2/4/8 bytes etc.
EDIT: Note, this method is not endian proof - you'd need to flip the values in that case.
struct double_nibble{ unsigned char x : 4; unsigned char y : 4; };void my_function(){ double_nibble dn; // Make sure that the size of the struct is actually a byte assert(sizeof(double_nibble) == 1); dn.x = 11; dn.y = 10;}The one problem I have with this method is making sure that the compiler gives me the right size data structure (hence the assert), sometimes they tend to pad structures out to 2/4/8 bytes etc.
EDIT: Note, this method is not endian proof - you'd need to flip the values in that case.
Quote:
Original post by TDragon
CTar -- don't forget your bit shift for extracting the high part.
No because I &(and) with 240 (11110000 in binary), this should provide slightly better performance (not that I tried to make these functions efficient then I could have made function too which assumed the char only was 4 bit and didn't bother and'ing etc.), but you could of course just do this:
unsigned char ExtractHighPart(unsigned char PackedChar){ return (PackedChar>>4)&15;}Quote:
Original post by TDragon Quote:Yes, it would.
P.S. Would this be done differently on Big Endian and Little endian processors?
No it wouldn't matter a bit if you're only using 8-bit values.
If you were using 16 or 32-bit values, then the endianess comes into play (because byte 0 would be swapped for the different endianess's on 16 or 32-bit bit), but the bit positions are always the same within a byte.
Quote:
Original post by arm
The one problem I have with this method is making sure that the compiler gives me the right size data structure (hence the assert), sometimes they tend to pad structures out to 2/4/8 bytes etc.
Most compilers that pad structs will always pad them - not sometimes. You can usally specify the byte alingment boundaries for all structs in the app with a command line switch, or for individual structs with a pragma in some compilers or a special attribute keyword in other compilers. Look in your compiler's documentation and see which it uses and get rid of that assert!
Quote:
EDIT: Note, this method is not endian proof - you'd need to flip the values in that case.
Actually, no. When using a bitfield the member values will always be referenced the same: mybitfield.x and mybitfield.y will always return the appropriate value. Endianess has no influence on bitfields. In fact, the ordering of bitfields is undefined in the C spec and is implementation dependent. The compiler may pack the fields from hi to lo, or from lo to hi, in the order you declare them, in reverse order, or in some mixed order, no matter the endianess of the system. All you need do is reference the bitfield members by name and it will work. You will most likely never need to worry about the ordering of the bitfield.
Quote:
Most compilers that pad structs will always pad them - not sometimes. You can usally specify the byte alingment boundaries for all structs in the app with a command line switch, or for individual structs with a pragma in some compilers or a special attribute keyword in other compilers. Look in your compiler's documentation and see which it uses and get rid of that assert!
When I use the word 'sometimes' I mean that some compilers pad differently to others, which could cause problems when porting code. Also, all of those #pragma's are compiler-specific which is really going to give you a hard time if you are porting to a different platform (with different endianess) which doesn't have your specific brand of compiler. I think I'll keep that assert for now! At least its going to be supported over different compilers, AND, only rears its ugly head during debug.
Quote:
Actually, no. When using a bitfield the member values will always be referenced the same: mybitfield.x and mybitfield.y will always return the appropriate value. Endianess has no influence on bitfields. In fact, the ordering of bitfields is undefined in the C spec and is implementation dependent. The compiler may pack the fields from hi to lo, or from lo to hi, in the order you declare them, in reverse order, or in some mixed order, no matter the endianess of the system. All you need do is reference the bitfield members by name and it will work. You will most likely never need to worry about the ordering of the bitfield.
The fact that the C-spec is so loosely defined for bitfields would just make the problems of endianess even worse in this example. Imagine you write a binary file on a big-endian machine then read it in on a small-endian machine, using a different brand of compiler for each machine. Now there's absolutely no garantee of the fields matching up!
It is for this reason that I can not recommend my bitfield method for cross-platform/compiler portable code. Keep bitfields for internal and/or same-platform use.
arm.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement