Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #9776 > unrolled thread

Bit-field union bug

Started byQuentin Pope <qp19433@hotmail.NOSPAM.com>
First post2011-08-31 21:23 +0000
Last post2011-09-01 16:27 -0700
Articles 11 on this page of 31 — 17 participants

Back to article view | Back to comp.lang.c


Contents

  Bit-field union bug Quentin Pope <qp19433@hotmail.NOSPAM.com> - 2011-08-31 21:23 +0000
    Re: Bit-field union bug Keith Thompson <kst-u@mib.org> - 2011-08-31 14:34 -0700
      Re: Bit-field union bug Quentin Pope <qp19433@hotmail.NOSPAM.com> - 2011-09-03 19:06 +0000
        Re: Bit-field union bug Ian Collins <ian-news@hotmail.com> - 2011-09-04 08:19 +1200
          Re: Bit-field union bug Quentin Pope <qp19433@hotmail.NOSPAM.com> - 2011-09-03 21:12 +0000
            Re: Bit-field union bug Ben Bacarisse <ben.usenet@bsb.me.uk> - 2011-09-03 22:30 +0100
              Re: Bit-field union bug Ian Collins <ian-news@hotmail.com> - 2011-09-04 11:01 +1200
                Re: Bit-field union bug Ben Bacarisse <ben.usenet@bsb.me.uk> - 2011-09-04 00:37 +0100
                  Re: Bit-field union bug Phil Carmody <thefatphil_demunged@yahoo.co.uk> - 2011-09-06 00:36 +0300
              Re: Bit-field union bug Tim Rentsch <txr@alumni.caltech.edu> - 2012-01-24 12:23 -0800
                Re: Bit-field union bug Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-01-24 21:15 +0000
    Re: Bit-field union bug Ian Collins <ian-news@hotmail.com> - 2011-09-01 09:36 +1200
    Re: Bit-field union bug jacob navia <jacob@spamsink.net> - 2011-08-31 23:38 +0200
    Re: Bit-field union bug Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2011-08-31 15:42 -0600
      Re: Bit-field union bug Seebs <usenet-nospam@seebs.net> - 2011-08-31 21:57 +0000
        Re: Bit-field union bug James Kuyper <jameskuyper@verizon.net> - 2011-08-31 18:21 -0400
          Re: Bit-field union bug Seebs <usenet-nospam@seebs.net> - 2011-09-01 02:45 +0000
            Re: Bit-field union bug James Kuyper <jameskuyper@verizon.net> - 2011-09-01 06:37 -0400
          Re: Bit-field union bug Kenneth Brody <kenbrody@spamcop.net> - 2011-09-01 14:19 -0400
            Re: Bit-field union bug James Kuyper <jameskuyper@verizon.net> - 2011-09-01 14:46 -0400
        Re: Bit-field union bug Phil Carmody <thefatphil_demunged@yahoo.co.uk> - 2011-09-01 15:34 +0300
          Re: Bit-field union bug Keith Thompson <kst-u@mib.org> - 2011-09-01 07:24 -0700
    Re: Bit-field union bug James Kuyper <jameskuyper@verizon.net> - 2011-08-31 17:55 -0400
    Re: Bit-field union bug "Scott Fluhrer" <sfluhrer@ix.netcom.com> - 2011-08-31 19:01 -0400
    Re: Bit-field union bug Peter Nilsson <airia@acay.com.au> - 2011-08-31 16:03 -0700
      Re: Bit-field union bug David Thompson <dave.thompson2@verizon.net> - 2011-09-06 01:13 -0400
        Re: Bit-field union bug Tim Rentsch <txr@alumni.caltech.edu> - 2012-01-24 12:17 -0800
          Re: Bit-field union bug ec429 <ec429@cam.ac.uk> - 2012-01-25 00:13 +0000
            Re: Bit-field union bug Kaz Kylheku <kaz@kylheku.com> - 2012-01-25 00:36 +0000
            Re: Bit-field union bug Tim Rentsch <txr@alumni.caltech.edu> - 2012-01-31 14:54 -0800
    Re: Bit-field union bug Andrey Tarasevich <andreytarasevich@hotmail.com> - 2011-09-01 16:27 -0700

Page 2 of 2 — ← Prev page 1 [2]


#9808

FromPhil Carmody <thefatphil_demunged@yahoo.co.uk>
Date2011-09-01 15:34 +0300
Message-ID<8762lca1bl.fsf@bazspaz.fatphil.org>
In reply to#9782
Seebs <usenet-nospam@seebs.net> writes:
> On 2011-08-31, Joe Pfeiffer <pfeiffer@cs.nmsu.edu> 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

[toc] | [prev] | [next] | [standalone]


#9812

FromKeith Thompson <kst-u@mib.org>
Date2011-09-01 07:24 -0700
Message-ID<ln1uw0tk73.fsf@nuthaus.mib.org>
In reply to#9808
Phil Carmody <thefatphil_demunged@yahoo.co.uk> writes:
> Seebs <usenet-nospam@seebs.net> writes:
>> On 2011-08-31, Joe Pfeiffer <pfeiffer@cs.nmsu.edu> 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) kst-u@mib.org  <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"

[toc] | [prev] | [next] | [standalone]


#9781

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-08-31 17:55 -0400
Message-ID<4E5EADE5.6010701@verizon.net>
In reply to#9776
On 08/31/2011 05: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;
>    };

Ian has already pointed out to you the syntax errors in that declaration.

> };

"An implementation may allocate any addressable storage unit large
enough to hold a bit-field. 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." (6.7.2.1p10)

However, the thing that follows proto is not another bit field, but a
union. The union contains two structs, both structs contain bit fields,
but those bit fields are not members of the same struct that proto is.
Therefore, 6.7.2.1p10 does not apply.

Here's an alternative approach that should cause the fields to be merged
into the same storage unit. However, there's no guarantees about what
size the "storage unit" is. It could have a size of 8.

	struct s_skip_ind {
	   unsigned proto:4;
	   unsigned skip_ind:4;
	};

	struct s_trans_id {
	   unsigned proto:4;
	   unsigned trans_val:3;
	   unsigned trans_id:1;
	};
	
	union foo {
	   struct s_skip_ind skip_ind;
	   struct s_trans_id trans_id;
	};


Note that, with this definition, both 'proto's are required to occupy
the same bits (6.5.2.3p5).

[toc] | [prev] | [next] | [standalone]


#9786

From"Scott Fluhrer" <sfluhrer@ix.netcom.com>
Date2011-08-31 19:01 -0400
Message-ID<1314831715.648791@rcdn-nntpcache-2>
In reply to#9776
"Quentin Pope" <qp19433@hotmail.NOSPAM.com> wrote in message 
news:j3m8np$8gv$1@speranza.aioe.org...
> 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.

Actually, I don't think that the compiler is allowed to coalesce them.  You 
made skip_ind and trans_id structures, which means that you are allowed to 
have pointers to them, as in:

    struct foo example;
    struct s_skip_id *p = &example.skip_ind;

You may have no intention of doing so, but the compiler doesn't know that. 
Because all pointers must be on byte boundaries, this means that these 
structures must be placed on byte boundaries.

>
>
> 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;
>   };
> }; 

[toc] | [prev] | [next] | [standalone]


#9787

FromPeter Nilsson <airia@acay.com.au>
Date2011-08-31 16:03 -0700
Message-ID<610e0e48-76c6-476b-8303-2c0055781cdc@s35g2000prm.googlegroups.com>
In reply to#9776
Quentin Pope <qp19...@hotmail.NOSPAM.com> wrote:
> On my compiler, the output of "sizeof(foo)" of the following
> is 8, instead of 4.

Did your compiler issue the required diagnostic?

> 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.

Depends whether you're using a conforming C compiler or not.

> 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;

C doesn't act like C++ when it comes to struct tags.

>    };

C doesn't allow unnamed members in structs and unions, with the
exception of zero width bit-fields.

> };

If we replace this with...

  struct foo {
     unsigned proto:4;
     union {
        struct s_skip_ind skip_ind;
        struct s_trans_id trans_id;
     } u;
  };

...then you should realise that a conforming C compiler must be
able to  support the following...

  struct foo f;
  union {
    struct s_skip_ind skip_ind;
    struct s_trans_id trans_id;
  } *up = &f.u;

It would make the compiler's life a tad difficult if it had to
support that _and_ coalesce bit-fields in the way you would like.

See James Kuyper's response for an alternative method.

--
Peter

[toc] | [prev] | [next] | [standalone]


#9959

FromDavid Thompson <dave.thompson2@verizon.net>
Date2011-09-06 01:13 -0400
Message-ID<gvab67hq7evufs0upu3aliat65c14bofqu@4ax.com>
In reply to#9787
On Wed, 31 Aug 2011 16:03:14 -0700 (PDT), Peter Nilsson
<airia@acay.com.au> wrote:

> If we replace this with...
> 
>   struct foo {
>      unsigned proto:4;
>      union {
>         struct s_skip_ind skip_ind;
>         struct s_trans_id trans_id;
>      } u;
>   };
> 
> ...then you should realise that a conforming C compiler must be
> able to  support the following...
> 
>   struct foo f;
>   union {
>     struct s_skip_ind skip_ind;
>     struct s_trans_id trans_id;
>   } *up = &f.u;
> 
> It would make the compiler's life a tad difficult if it had to
> support that _and_ coalesce bit-fields in the way you would like.
> 
Yes but no. Yes foo.u must be addressable preventing bit-field
packing. No you can't use &f.u that way. 

<topic shift>
*Within a translation unit*, two declarations/definitions of struct or
union types with the same contents are *not* formally compatible
types. In practice a sane compiler will lay them out the same (unless
you alter something like #pragma pack) and so accesses will work if
you cast, but you need a tag or typedef to cast.

*Between translation units* if the tag, member names and types are the
same, it is completely compatible.

[toc] | [prev] | [next] | [standalone]


#16114

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-01-24 12:17 -0800
Message-ID<kfnhazkhn3h.fsf@x-alumni2.alumni.caltech.edu>
In reply to#9959
David Thompson <dave.thompson2@verizon.net> writes:

> <topic shift>
> *Within a translation unit*, two declarations/definitions of struct or
> union types with the same contents are *not* formally compatible
> types. In practice a sane compiler will lay them out the same (unless
> you alter something like #pragma pack) and so accesses will work if
> you cast, but you need a tag or typedef to cast.

Identical layout is not enough to make things work in
the presence of type-sensitive optimization.  In the
past one could generally get away with such things,
but that's becoming less true as time goes on.

[toc] | [prev] | [next] | [standalone]


#16144

Fromec429 <ec429@cam.ac.uk>
Date2012-01-25 00:13 +0000
Message-ID<jfnhg7$ahl$1@dont-email.me>
In reply to#16114
On 24/01/12 20:17, Tim Rentsch wrote:
> Identical layout is not enough to make things work in
> the presence of type-sensitive optimization.  In the
> past one could generally get away with such things,
> but that's becoming less true as time goes on.
Why is this?  If the two struct (say) types have been defined 
identically, what optimisation can the compiler possibly make that'll be 
valid for one but not the other?
-e
-- 
'sane', adj.: see 'unimaginative'
   on the web - http://jttlov.no-ip.org

[toc] | [prev] | [next] | [standalone]


#16150

FromKaz Kylheku <kaz@kylheku.com>
Date2012-01-25 00:36 +0000
Message-ID<20120124163119.715@kylheku.com>
In reply to#16144
On 2012-01-25, ec429 <ec429@cam.ac.uk> wrote:
> On 24/01/12 20:17, Tim Rentsch wrote:
>> Identical layout is not enough to make things work in
>> the presence of type-sensitive optimization.  In the
>> past one could generally get away with such things,
>> but that's becoming less true as time goes on.
> Why is this?  If the two struct (say) types have been defined 
> identically, what optimisation can the compiler possibly make that'll be 
> valid for one but not the other?

It can assume that foo->x = 42 has no effect on the value of bar->x, continuing
to use a stale cached value, because foo and bar are pointers to different
declared structure types.

[toc] | [prev] | [next] | [standalone]


#16530

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-01-31 14:54 -0800
Message-ID<kfnty3b1o15.fsf@x-alumni2.alumni.caltech.edu>
In reply to#16144
ec429 <ec429@cam.ac.uk> writes:

> On 24/01/12 20:17, Tim Rentsch wrote:
>> Identical layout is not enough to make things work in
>> the presence of type-sensitive optimization.  In the
>> past one could generally get away with such things,
>> but that's becoming less true as time goes on.
>
> Why is this?  If the two struct (say) types have been defined
> identically, what optimisation can the compiler possibly make that'll
> be valid for one but not the other?

What Kaz Kylheku said -- stores into one kind of struct can
be assumed not to affect members in a different kind of
struct, if the two structs involved are not both in a single
union object.  Note that this latter condition can happen
even if both struct types are included in a union but one
of the actual struct objects is known not to be in a union.
For example, compiling (I haven't actually compiled this,
please excuse any minor mistakes):

    struct foo { int x; ... };
    struct bas { int x; ... };
    union foobas { struct foo f; struct bas b; };
    extern struct foo global_foo = { 1 };

    int
    mumble( union foobas *p, struct bas *q  ){
        global_foo.x  = 7;

        q->x          = 13;
        p->b.x        = 14;
        p->f.x        = 15;

        return  global_foo.x;
    }

the compiler is allowed to assume the function will return
the value 7, because none of the intermediate assignments
can affect global_foo.x.  However, the three intermediate
assignments cannot be rearranged relative to each other,
because any one of them might affect the others.

[toc] | [prev] | [next] | [standalone]


#9846

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2011-09-01 16:27 -0700
Message-ID<j3p4cs$5a2$1@dont-email.me>
In reply to#9776
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

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.c


csiph-web