Click to See Complete Forum and Search --> : avoiding bitfields
seany
March 2nd, 2006, 09:21 AM
If I take the following struct:
struct x
{
unsigned char t;
unsigned char w;
unsigned char a;
};
If this struct is used to create a byte for output to a file and from the above struct t is 4 bits and occupies the MSBs, w is 2 bits and a is 2 bits following.
What is the best way using bitwise and shift operations for me to achieve the right structure in the resulting byte.
philkr
March 2nd, 2006, 09:40 AM
If t, w, a is the right order where t is in the most significant bits it's like that:
unsigned char byte = ((x.t & 15) << 4) | ((x.w & 3) << 2) | (x.a & 3);
I am assuming that the least significant bits are used in the source struct.
seany
March 2nd, 2006, 04:00 PM
thank you for your last response.
can u tell me what you mean when you say
>>I am assuming that the least significant bits are used in the source struct.
Does it matter if they are not?
philkr
March 3rd, 2006, 03:04 AM
thank you for your last response.
can u tell me what you mean when you say
>>I am assuming that the least significant bits are used in the source struct.
Does it matter if they are not?
You said that t is 4 bits, but since you don't want to use bitfields you declare it as a unsigned char (8 bit). That means that four other bits are meaningless (for w and a it is 6 bits). Now you have the choice which bits you set for the value. And normally you would take the least significant bits, because you can then read the value directly and don't have to shift the bits. An example:
You only want to use 4 bits of t = 0. Then you have several possibilities:
XXXX0000 XXX0000X XX0000XX X0000XXX 0000XXXX
But the first one is the best because you can simply cut the meaningless unused XXXX bits away with a bitwise and-operator ( & 15) and then have the right value. And if you want to set a value you can do a simply assingment like "t = 3;"
dude_1967
March 3rd, 2006, 07:12 AM
seany,
philkr,
I believe that seany is trying to manipulate something like a 12-bit unsigned integer.
philkr, I think you might have forgotten to mask, carry and borrow digits. Also, I believe that your solution makes assumptions about the internal storage convention used by the compiler. Based on the seany's previous posts, this might be of some concern.
If the data structure represents a 12-bit unsigned integer, it is necessary to shift each data member and mask the upper nibble of the carry nibbles.
The mathematics would be something like this:
struct n12
{
unsigned char t;
unsigned char w;
unsigned char a;
n12 operator<<(const int n);
};
n12 n12::operator<<(const int n)
{
const n12 result =
{
((t << n) & 0x0F) | (((w << n) & 0xF0) >> 4),
((w << n) & 0x0F) | (((a << n) & 0xF0) >> 4),
((a << n) & 0x0F) & 0x0F
};
return result;
}
I did not fully check the function of the mathematics. This is only meant to give an idea of the kind of shift algorithm needed.
Sincerely, Chris. :)
seany
March 4th, 2006, 07:57 PM
What I am trying to achieve is to create a single byte from the structure above without using bitfields, by taking 4 bits from t, 2 bits from w and 2 bits from a.
philkr, dude_1967 - thanks for the help on this.
dude_1967
March 6th, 2006, 01:47 PM
seany,
Just remember the guidance which was given in your other post.
What you want to do can be done. However, the resulting implementation is not guaranteed to be portable.
Although strictly correct, the statement above can be appended.
Most compilers allow the user to force the allocation scheme for structures. For example using Microsoft compilers, there is the #pragma pack(...) definition as well as a command line option for this. For GNU there is something else. And for every high quality compiler for microcontroller targets, there should be this kind of support. Please consult your compiler manuals and try to determine if this option can be specified.
Furthermore note from the ISO ANSI C specification that, when successive bit-fields are defined and if they fit within the current allocation unit, then compiler must put them within the current allocation unit. However, they need not have a guaranteed order.
Finally note that, although there are grave differences between little-endian and big-endian storage conventions regarding bytes, it is very uncommon to find a compiler which breaks from the tradition of 0...7 bit-ordering.
You put all these appended conditions together and you can legitimately consider relying on bit-ordering for single-byte structures with bitfields as long as you can guarantee single-byte allignment and single-byte size without byte padding.
Although we recommend in our group not to rely on non-portable code, there can be reasons to do this. If you chose to do this for your design, then please document the code well and provide a way for others to identify the goal of the coding and which assumptions have led to this kind of coding.
And the structure, written in the C-language is:
typedef struct structMyByte
{
unsigned t : 4;
unsigned w : 2;
unsigned a : 2;
}
tMyByte;
Be sure to force single-byte allignment as well as single-byte size. You may have to use unsigned char if you are using a compiler for a microcontroller target.
Sincerely, Chris.
:thumb:
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.