Bit field assignments in C

I'm using a data structure in C like the following that contains a bit field and uses the colon to define the number of bits.

typedef bitfield{
  uchar x:6,
  uchar y:2;
  uchar z;
} BITFIELD;
//assume msb packing such that x is 6 most significant bits and y is 2 least sig. bits

In my code if I have a byte value and then assign it to the type members, will the least significant bits always be assigned to the bit field variable, or, will the assignment take into account the correct number of bits as shown below?

//pseudo code

BITFIELD mybitfield;

uchar data = 0xFC;   // 1111 1100

mybitfield.x = data;
mybitfield.y = data;
mybitfield.z = data;

at this point I think the following values are stored

mybitfield.x = 0x3F  //111111  six most sig. bits
mybitfield.y = 0x00 //00  two least sig. bits
mybitfield.z = 0xFC

Is this correct?

Thanks.
JohnSantaFeAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
phoffricConnect With a Mentor Commented:
On VS 2008 Express I looked at the memory changes as I stepped through your x,y,z assignments. You may be interested in knowing that the VS layout of bits are implemented so that:
x:6 are the 6 lsb of the first byte
y:2 are the 2 msb of the first byte
z is the 2nd byte
But, as I mentioned earlier, the layout is implementation dependent; so it could be different on your platform. For example, it could be that on your platform x:6 is the 6 msb of the first byte.

If you are planning on trying to use this bit-field approach for memory-mapped registers, then (1) I would be extremely careful; and (2) I would seriously consider using a more portable approach where you definitely control which bits are set.

In other words, if you care about where the bit-fields are placed in the word, then I would advise not using bit-fields.
0
 
JohnSantaFeAuthor Commented:
Quick update which might make a difference, the structure is actually:

typedef bitfield{
  uchar x:6,
             y:2;
  uchar z;
} BITFIELD;

(note the comma after the 6)
0
 
phoffricCommented:
I get your results using VS 2008 Express. But according to ANSI C K&R book "Almost everything about about fields is implementation dependent. Whether a field may overlap a word boundary is implementation-defined. ... Fields are assigned left to right on some machines and right to left on others. This means that although fields are useful for maintaining internally-defined data structures, the question of which end comes first has to be be carefully considered when picking apart externally defined data; programs that depend such things are not portable."
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
phoffricCommented:
Perhaps you would like to explore another way to pack your data, say by shifts and masks?
0
 
phoffricCommented:
Are you writing in C or C++ ? I can take a look at the C99 standard to see if there's an update to what K&R wrote in their ANSI C book.
0
 
phoffricCommented:
I'm sorry - there was a spec on my monitor or my eyes.
mybitfield.x = 0x3C
mybitfield.y = 0x00
mybitfield.z = 0xFC

This is what I would expect no matter what internal representation your compiler would have.

uchar data = 0xFC;   // 1111 1100
taking the 6 bits of data gives 11 1100 which is 3C
taking the 2 bits of data gives          00  which is 0
taking the 8 bits of data of course gives data which is 0xFC;
0
 
Infinity08Commented:
First of all, use unsigned int's for bit fields, rather than unsigned char's (which I assume is what you mean by uchar's). Whether unsigned char's are allowed for bit fields, is implementation defined, and so it's best not to depend on it.

Second, bit fields, pretty much act like integers of a limited width, so assigning a value to a bit field, is like assigning a value to an integer (of the same type as the one used for the bit field), so :

>> mybitfield.x = 0x3F  //111111  six most sig. bits

the result would be 0x3C, rather than 0x3F.
0
 
phoffricCommented:
>> Quick update which might make a difference,
No difference with the comma or with your OP.
0
 
phoffricCommented:
I looked up bit-fields in C99 to see if there was any tightening up of the bit allocation rules. What I said in my previous post still applies. Here is an excerpt:

"6.7.2.1 Structure and union specifiers...10 An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a
structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
implementation-defined. The order of allocation of bit-fields within a unit (high-order tolow-order or low-order to high-order) is implementation-defined. The alignment of the
addressable storage unit is unspecified."

0
 
JohnSantaFeAuthor Commented:
Thanks for the excellent research!

I'm using this for a communications protocol, specifically IPMI.  This type of structure is used in the open source coreIPM software.

With my platform being a big endian ARM processor I expect the six bits will be the msb's.

Because this is an unsigned char and there are no other bit fields in the structure, I'm feeling like it's pretty safe, but I agree shifting and masking seems safer.
0
 
JeepGuyCommented:
I have done quite a bit of comm work with unique ICDs where I have to mess with individual bits and I prefer to do bit masking & shifting.  It's ugly (or pretty, if you're twisted like me ;-), but I prefer it.  Also remember that the MS compiler (and probably others) will pad the size of your struct when defining bit fields using any variable larger than a char.  For example:

typedef struct
{
    unsigned short a:4;
    unsigend short b:4;
    unsigned short c: 4;
    unsigned short d:4;
    unsigned char e;
}some_struct;

......will NOT be 24 bytes in size (where a short is 2 bytes and a char is 1 byte).  It will actually be 32 bytes, because the compiler will pad it.  The size of structs are very important in comm software, so you can see where this would be a problem, especially if you're dealing with messages that are an odd number in size.
0
 
JeepGuyCommented:
I'm mixing up bytes with bits.  I meant to say....

That struct will NOT be 3 bytes in size (or 24 bits).  It will actually be 4 bytes in size (32 bits).
0
 
phoffricCommented:
>> With my platform being a big endian ARM processor I expect the six bits will be the msb's.
Usually big endian refers to byte order rather than bit order. So, while the six bits might be the msb's, in general, on a big endian machine, it doesn't have to be. For that matter, there would not have been a contradiction if I found that the 6 bits were allocated in the msb's. It's platform dependent. In fact, by platform, I believe that really means compiler dependent. So, on the same machine, two different compiler vendors would have the right, I think, to allocate the internal bit allocation in any group as they wish subject to the restrictions in the above C99 quote that I referenced.
0
 
Infinity08Commented:
The accepted post does not actually answer the question. The question was :

>> at this point I think the following values are stored
>> <SNIP>
>> Is this correct?

This has nothing to do with how the bit fields are allocated within the struct. The only two posts that answer this correctly, are http:#29269068 and http:#29269146.

So, be careful to not draw the wrong conclusions here.
0
All Courses

From novice to tech pro — start learning today.