Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Bit-field union bug

Reply
Thread Tools

Bit-field union bug

 
 
James Kuyper
Guest
Posts: n/a
 
      09-01-2011
On 08/31/2011 10:45 PM, Seebs wrote:
> On 2011-08-31, James Kuyper <(E-Mail Removed)> wrote:
>> Actually, it is required to do so, when adjacent bit-fields in the same
>> struct fit in a single storage unit (6.7.2.1p10).

....
> In fact, so far as I can tell, it's *not* permissible to coalesce adjacent
> structs.


Of course. That was apparently not as obvious to the OP as it seems to me.
--
James Kuyper
 
Reply With Quote
 
 
 
 
Phil Carmody
Guest
Posts: n/a
 
      09-01-2011
Seebs <(E-Mail Removed)> writes:
> On 2011-08-31, Joe Pfeiffer <(E-Mail Removed)> wrote:
> > While I would agree with you, the standard disagrees with both of us.
> > I'm not quite sure what the point of a bitfield is when the compiler is
> > free to insert arbitrary padding between elements, but that is indeed
> > the case.

>
> The point is that the compiler is *permitted* to coalesce bitfields.


The second thing wasn't a bitfield, it was a union.

I would have been very surprised if the size hadn't been at least 8.
On something like a Cray, I'd not have blinked if it had been 16 bytes.
(Keith - you've used a Cray most recently, I think - can you shed any
light on that?)

Phil
--
"Religion is what keeps the poor from murdering the rich."
-- Napoleon
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      09-01-2011
Phil Carmody <(E-Mail Removed)> writes:
> Seebs <(E-Mail Removed)> writes:
>> On 2011-08-31, Joe Pfeiffer <(E-Mail Removed)> wrote:
>> > While I would agree with you, the standard disagrees with both of us.
>> > I'm not quite sure what the point of a bitfield is when the compiler is
>> > free to insert arbitrary padding between elements, but that is indeed
>> > the case.

>>
>> The point is that the compiler is *permitted* to coalesce bitfields.

>
> The second thing wasn't a bitfield, it was a union.
>
> I would have been very surprised if the size hadn't been at least 8.
> On something like a Cray, I'd not have blinked if it had been 16 bytes.
> (Keith - you've used a Cray most recently, I think - can you shed any
> light on that?)


Not on bit fields, sorry.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      09-01-2011
On 09/01/2011 02:19 PM, Kenneth Brody wrote:
> On 8/31/2011 6:21 PM, James Kuyper wrote:
>> On 08/31/2011 05:57 PM, Seebs wrote:
>>> On 2011-08-31, Joe Pfeiffer<(E-Mail Removed)> wrote:
>>>> While I would agree with you, the standard disagrees with both of us.
>>>> I'm not quite sure what the point of a bitfield is when the compiler is
>>>> free to insert arbitrary padding between elements, but that is indeed
>>>> the case.
>>>
>>> The point is that the compiler is *permitted* to coalesce bitfields. But
>>> not required to, because some systems really don't provide meaningful support
>>> for them.

>>
>> Actually, it is required to do so, when adjacent bit-fields in the same
>> struct fit in a single storage unit (6.7.2.1p10). And since CHAR_BIT is
>> required to be>=8, these bit-fields, had they been in the same struct,
>> would have been required to be stored in adjacent bits of the same
>> storage unit.

>
> But, this is not two bit-fields. Here's the original code:


I already raised that point in an earlier message. In this message I was
dealing with a different point.

In the case described by the OP, a compiler is prohibited from
coalescing "proto" with any of the other bit-fields, because if the
unnamed union member had been given a name (as it should have been),
that member would have been required to have a distinct address.

However, in the case which I was referring to above, "adjacent
bit-fields in the same struct", it's not merely permitted to coalesce
such bit-fields, it's required to do so, if it can.

Either way, "permitted" was an incorrect description.
 
Reply With Quote
 
Andrey Tarasevich
Guest
Posts: n/a
 
      09-01-2011
On 8/31/2011 2:23 PM, Quentin Pope wrote:
> On my compiler, the output of "sizeof(foo)" of the following is 8,
> instead of 4.
>
> Which indicates that the compiler is aligning the union at
> the next int boundary, rather than coalescing it with "proto".
>
> I think this is a bug.
>
> struct s_skip_ind {
> unsigned skip_ind:4;
> };
>
> struct s_trans_id {
> unsigned trans_val:3;
> unsigned trans_id:1;
> };
>
> struct foo {
> unsigned proto:4;
> union {
> s_skip_ind skip_ind;
> s_trans_id trans_id;
> };
> };


No. You are making invalid conclusions from translating invalid code.

C language does not allow anonymous union members in the struct
declaration. Your declaration of `struct foo` is invalid C. If your
compiler accepted this declaration, it is a mere compiler-specific
extension, which has nothing to do with standard C language.

In C language you are required to give that union member an explicit
name, as in

struct foo {
unsigned proto:4;
union {
s_skip_ind skip_ind;
s_trans_id trans_id;
} u; /* <- the name is required */
};

Now note that the above member `u` should have its own offset and its
own address within `struct foo`, since at any place in your code you can
something like

struct foo f;
void *p = &f.u;

For this reason, the compiler simply cannot merge this union member with
the previous bit-field. It has too align `u` at the beginning of an
addressable memory unit.

Apparently your compiler was forgiving enough to let you (illegally)
omit the member name, but wasn't brave enough to take the next step and
do the merging.

In any case, if there is any compiler bug here, it is the failure of the
compiler to report the illegal anonymous union member, not the failure
to merge the bit-fields.

--
Best regards,
Andrey Tarasevich

 
Reply With Quote
 
Quentin Pope
Guest
Posts: n/a
 
      09-03-2011
On Wed, 31 Aug 2011 14:34:09 -0700, Keith Thompson wrote:
> Quentin Pope <(E-Mail Removed)> writes:
>> On my compiler, the output of "sizeof(foo)" of the following is 8,
>> instead of 4.
>>
>> Which indicates that the compiler is aligning the union at the next int
>> boundary, rather than coalescing it with "proto".
>>
>> I think this is a bug.
>>
>>
>> struct s_skip_ind {
>> unsigned skip_ind:4;
>> };
>>
>> struct s_trans_id {
>> unsigned trans_val:3;
>> unsigned trans_id:1;
>> };
>>
>> struct foo {
>> unsigned proto:4;
>> union {
>> s_skip_ind skip_ind;
>> s_trans_id trans_id;
>> };
>> };

>
> Whether it's a bug or not, it's not a violation of the C standard.
> Compilers can legally insert arbitrary padding between any two members
> of a struct, or after the last one.
>
> I think I've seen some compilers that use the declared type of a bit
> field to determine its alignment; for example, given
> unsigned char x:1
> unsigned short y:1
> unsigned int z:1
> x, y, and z might be aligned on 1-byte, 2-byte, and 4-byte boundaries,
> respectively. I don't think there's any support for this in the
> standard, which only requires support for bit fields of types int,
> signed int, unsigned int, and (new in C99) _Bool.


I see.

In this case, is there an equivalent of the offsetOf() function for
bitfield members, to allow programmers to determine whether or not
bitfields have been packed?

Cheers
QP
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      09-03-2011
On 09/ 4/11 07:06 AM, Quentin Pope wrote:
> On Wed, 31 Aug 2011 14:34:09 -0700, Keith Thompson wrote:
>> Quentin Pope<(E-Mail Removed)> writes:
>>> On my compiler, the output of "sizeof(foo)" of the following is 8,
>>> instead of 4.
>>>
>>> Which indicates that the compiler is aligning the union at the next int
>>> boundary, rather than coalescing it with "proto".

>>
>> Whether it's a bug or not, it's not a violation of the C standard.
>> Compilers can legally insert arbitrary padding between any two members
>> of a struct, or after the last one.
>>
>> I think I've seen some compilers that use the declared type of a bit
>> field to determine its alignment; for example, given
>> unsigned char x:1
>> unsigned short y:1
>> unsigned int z:1
>> x, y, and z might be aligned on 1-byte, 2-byte, and 4-byte boundaries,
>> respectively. I don't think there's any support for this in the
>> standard, which only requires support for bit fields of types int,
>> signed int, unsigned int, and (new in C99) _Bool.

>
> I see.
>
> In this case, is there an equivalent of the offsetOf() function for
> bitfield members, to allow programmers to determine whether or not
> bitfields have been packed?


Won't the sizeof operator tell you?

--
Ian Collins
 
Reply With Quote
 
Quentin Pope
Guest
Posts: n/a
 
      09-03-2011
On Sun, 04 Sep 2011 08:19:58 +1200, Ian Collins wrote:
> On 09/ 4/11 07:06 AM, Quentin Pope wrote:
>> On Wed, 31 Aug 2011 14:34:09 -0700, Keith Thompson wrote:
>>> Quentin Pope<(E-Mail Removed)> writes:
>>>> On my compiler, the output of "sizeof(foo)" of the following is 8,
>>>> instead of 4.
>>>>
>>>> Which indicates that the compiler is aligning the union at the next
>>>> int boundary, rather than coalescing it with "proto".
>>>
>>> Whether it's a bug or not, it's not a violation of the C standard.
>>> Compilers can legally insert arbitrary padding between any two members
>>> of a struct, or after the last one.
>>>
>>> I think I've seen some compilers that use the declared type of a bit
>>> field to determine its alignment; for example, given
>>> unsigned char x:1
>>> unsigned short y:1
>>> unsigned int z:1
>>> x, y, and z might be aligned on 1-byte, 2-byte, and 4-byte boundaries,
>>> respectively. I don't think there's any support for this in the
>>> standard, which only requires support for bit fields of types int,
>>> signed int, unsigned int, and (new in C99) _Bool.

>>
>> I see.
>>
>> In this case, is there an equivalent of the offsetOf() function for
>> bitfield members, to allow programmers to determine whether or not
>> bitfields have been packed?

>
> Won't the sizeof operator tell you?


Not necessarily I don't think.

For example, imagine
struct foo {
unsigned short a:2;
unsigned short b:2;
unsigned short c:2;
unsigned short d:2;
};

If sizeOf(foo) is 3, then there is no way of telling whether a and b are
packed into 1 byte, or if it's b and c, or if it's c and d.

Cheers,
QP
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      09-03-2011
Quentin Pope <(E-Mail Removed)> writes:

> On Sun, 04 Sep 2011 08:19:58 +1200, Ian Collins wrote:
>> On 09/ 4/11 07:06 AM, Quentin Pope wrote:
>>> On Wed, 31 Aug 2011 14:34:09 -0700, Keith Thompson wrote:
>>>> Quentin Pope<(E-Mail Removed)> writes:
>>>>> On my compiler, the output of "sizeof(foo)" of the following is 8,
>>>>> instead of 4.
>>>>>
>>>>> Which indicates that the compiler is aligning the union at the next
>>>>> int boundary, rather than coalescing it with "proto".
>>>>
>>>> Whether it's a bug or not, it's not a violation of the C standard.
>>>> Compilers can legally insert arbitrary padding between any two members
>>>> of a struct, or after the last one.
>>>>
>>>> I think I've seen some compilers that use the declared type of a bit
>>>> field to determine its alignment; for example, given
>>>> unsigned char x:1
>>>> unsigned short y:1
>>>> unsigned int z:1
>>>> x, y, and z might be aligned on 1-byte, 2-byte, and 4-byte boundaries,
>>>> respectively. I don't think there's any support for this in the
>>>> standard, which only requires support for bit fields of types int,
>>>> signed int, unsigned int, and (new in C99) _Bool.
>>>
>>> I see.
>>>
>>> In this case, is there an equivalent of the offsetOf() function for
>>> bitfield members, to allow programmers to determine whether or not
>>> bitfields have been packed?

>>
>> Won't the sizeof operator tell you?

>
> Not necessarily I don't think.
>
> For example, imagine
> struct foo {
> unsigned short a:2;
> unsigned short b:2;
> unsigned short c:2;
> unsigned short d:2;
> };
>
> If sizeOf(foo) is 3, then there is no way of telling whether a and b are
> packed into 1 byte, or if it's b and c, or if it's c and d.


Your point is valid but the example is not a good one. First, by using
unsigned short you've gone outside of standard C -- anything is
possible. If you were to replace short with int, then you would get
much more than think you might think you do:

In the "unsigned int" version, the C standard says that a, b, c and d
must be packed together, consecutively, in the first byte of the struct.
The "addressable storage unit" into which they get packed can't be less
than 1 byte in size and a byte can't be less than 8 bits wide. Which
one goes in the high-significance position is not specified but it is
must be either a or d and the other must follow in order.

However, I think it is often the case that code that needs to know how
bit fields are packed is using them beyond their natural purpose.
Shifting and masking gives you far more control over how things pack and
is usually the way to go when it matters.

--
Ben.
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      09-03-2011
On 09/ 4/11 09:30 AM, Ben Bacarisse wrote:
>
> However, I think it is often the case that code that needs to know how
> bit fields are packed is using them beyond their natural purpose.
> Shifting and masking gives you far more control over how things pack and
> is usually the way to go when it matters.


Or the code is written based on knowledge of the compiler being used. I
have often used bit fields to map hardware registers or bits in messages
headers.

--
Ian Collins
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
*bug* *bug* *bug* David Raleigh Arnold Firefox 12 04-02-2007 03:13 AM
SQL UNION -like filtering of offline DataSet into DataView for WebControl binding Marco Ippolito ASP .Net 2 05-19-2004 12:35 AM
union in struct without union name Peter Dunker C Programming 2 04-26-2004 07:23 PM
map XML union to C union (and vice-versa) Matt Garman XML 1 04-25-2004 12:40 AM
THE STATE OF THE UNION Jenna Bush MCSE 95 01-30-2004 02:02 PM



Advertisments