views:

1021

answers:

3

Hi,

I'm new to working with bits. I'm trying to work with an existing protocol, which can send three different types of messages.

Type 1 is a 16-bit structure:

struct digital 
{
 unsigned int type:2;
 unsigned int highlow:1;
 unsigned int sig1:5;
 unsigned int :1;
 unsigned int sig2:7;
};

The first two bits (type, in my struct above) are always 1 0 . The third bit, highlow, determines whether the signal is on or off, and sig1 + sig2 together define the 12-bit index of the signal. This index is split across the two bytes by a 0, which is always in bit 7.

Type 2 is a 32-bit structure. It has a 2-bit type, a 10-bit index and a 16-bit value, interspersed with 0's at positions 27, 23, 15 & 7. A bit-field struct representation would like something like this:

struct analog 
{
 unsigned int type:2;
 unsigned int val1:2;
 unsigned int :1;
 unsigned int sig1:3;
 unsigned int :1;
 unsigned int sig2:7;
 unsigned int :1;
 unsigned int val2:7;
 unsigned int :1;
 unsigned int val3:7;
};

sig1 & sig2 together form the 10-bit index. val1 + val2 + val3 together form the 16-bit value of the signal at the 10-bit index.

If I understand how to work with the first two structs, I think I can figure out the third.

My question is, is there a way to assign a single value and have the program work out the bits that need to go into val1, val2 and val3?

I've read about bit shifting, bit-field structs and padding with 0's. The struct seems like the way to go, but I'm not sure how to implement it. None of the examples of bit-packing that I've seen have values that are split the way these are. Ultimately, I'd like to be able to create an analog struct, assign an index (i = 252) and a value (v = 32768) and be done with it.

If someone could suggest the appropriate method or provide a link to a similar sample, I'd greatly appreciate it. If it matters, this code will be incorporated into a larger Objective-C app.

Thanks.

Brad

+2  A: 

You can do it with a series of shifts, ands, and ors. I have done the 10-bit index part for Type 2:

unsigned int i = 252;

analog a = (analog)(((i << 16) & 0x7f0000) | (i << 17) & 0x7000000);

Essentially, what this code does is shift the 10 bits of interest in int i to the range 16 - 25, then it ands it with the bitmask 0x7f0000 to set bits 22 - 31 to zero. It also shifts another copy of the 10 bits to the range 17 - 26, then it ands it with the bitmask 0x7000000 to set bits 0 - 22 and 26 - 31 to zero. Then it ors the two values together to create your desired zero-separated value.

.. I'm not absolutely sure that I counted the bitmasks correctly, but I hope you've got the idea. Just shift, and-mask, and or-merge.

Edit: Method 2:

analog a;
a.sig1 = (i & 0x7f); // mask out bit 8 onwards
a.sig2 = ((i<<1) & 0x700); // shift left by one, then mask out bits 0-8

On second thought method 2 is more readable, so you should probably use this.

int3
Thanks for the response. Is there any way to do it with bit-field structs?
Brad
Yeah.. see edit.
int3
A: 

You don't have to do this, this is where the union keyword comes in - you can specify all the bits out at the same time, or by referring to the same bits with a different name, set them all at once.

Paul Betts
A union won't magically allow you to put zeros in your bit patterns..
int3
A: 

You shouldn't use C structure bitfields because the physical layout of bitfields is undefined. While you could figure out what your compiler is doing and get your layout to match the underlying data, the code may not work if you switch to a different compiler or even update your compiler.

I know it's a pain, but do the bit manipulation yourself.

R Samuel Klatchko
There are cases where using a bitfield to parse a message is perfectly reasonable. For instance in embedded apps where the program is tied closely to the DSP chip's capabilities, there is no reason to worry about portability, since an platform change would break everything. Figuring out how the compiler handles bitfields, and taking advantage of it allows you to write much cleaner code.
AShelly