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


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

List of undefined behaviour and other sneeky bugs

Started byJohn Reye <jononanon@googlemail.com>
First post2012-05-03 10:04 -0700
Last post2012-05-08 06:19 -0700
Articles 20 on this page of 57 — 12 participants

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


Contents

  List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 10:04 -0700
    Re: List of undefined behaviour and other sneeky bugs jt@toerring.de (Jens Thoms Toerring) - 2012-05-03 17:38 +0000
      Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 10:50 -0700
        Re: List of undefined behaviour and other sneeky bugs Ben Pfaff <blp@cs.stanford.edu> - 2012-05-03 11:09 -0700
          Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 11:18 -0700
            Re: List of undefined behaviour and other sneeky bugs Ben Pfaff <blp@cs.stanford.edu> - 2012-05-03 11:24 -0700
              Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 11:35 -0700
                Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 11:56 -0700
                Re: List of undefined behaviour and other sneeky bugs Ben Pfaff <blp@cs.stanford.edu> - 2012-05-03 12:16 -0700
                  Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 12:20 -0700
                    Re: List of undefined behaviour and other sneeky bugs Keith Thompson <kst-u@mib.org> - 2012-05-03 12:39 -0700
            Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 17:51 -0700
              Re: List of undefined behaviour and other sneeky bugs "Joachim Schmitz" <nospam.jojo@schmitz-digital.de> - 2012-05-08 09:10 +0200
                Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-08 05:31 -0700
        Re: List of undefined behaviour and other sneeky bugs jt@toerring.de (Jens Thoms Toerring) - 2012-05-03 18:11 +0000
          Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 11:29 -0700
            Re: List of undefined behaviour and other sneeky bugs jt@toerring.de (Jens Thoms Toerring) - 2012-05-03 19:19 +0000
              Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 13:31 -0700
                Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 14:18 -0700
                  Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 15:20 -0700
              Re: List of undefined behaviour and other sneeky bugs Nobody <nobody@nowhere.com> - 2012-05-04 01:47 +0100
        Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 17:47 -0700
      Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 17:45 -0700
        Re: List of undefined behaviour and other sneeky bugs nick_keighley_nospam@hotmail.com - 2012-05-08 00:43 -0700
          Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-08 06:17 -0700
    Re: List of undefined behaviour and other sneeky bugs Keith Thompson <kst-u@mib.org> - 2012-05-03 12:46 -0700
      Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 13:35 -0700
        Re: List of undefined behaviour and other sneeky bugs Ben Pfaff <blp@cs.stanford.edu> - 2012-05-03 14:05 -0700
          Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 14:11 -0700
            Re: List of undefined behaviour and other sneeky bugs Ben Pfaff <blp@cs.stanford.edu> - 2012-05-03 15:02 -0700
              Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 18:10 -0700
                Re: List of undefined behaviour and other sneeky bugs nick_keighley_nospam@hotmail.com - 2012-05-08 00:49 -0700
                  Re: List of undefined behaviour and other sneeky bugs James Kuyper <jameskuyper@verizon.net> - 2012-05-08 06:37 -0400
                    Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-08 07:49 -0700
                  Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-08 07:25 -0700
                Re: List of undefined behaviour and other sneeky bugs Ben Pfaff <blp@cs.stanford.edu> - 2012-05-08 09:46 -0700
            Re: List of undefined behaviour and other sneeky bugs James Kuyper <jameskuyper@verizon.net> - 2012-05-03 18:24 -0400
              Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 18:24 -0700
        Re: List of undefined behaviour and other sneeky bugs jt@toerring.de (Jens Thoms Toerring) - 2012-05-03 21:17 +0000
          Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 18:28 -0700
        Re: List of undefined behaviour and other sneeky bugs Keith Thompson <kst-u@mib.org> - 2012-05-03 15:54 -0700
        Re: List of undefined behaviour and other sneeky bugs Old Wolf <oldwolf@inspire.net.nz> - 2012-05-06 22:32 -0700
          Re: List of undefined behaviour and other sneeky bugs Jens Gustedt <jens.gustedt@loria.fr> - 2012-05-07 08:26 +0200
          Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 18:31 -0700
      Re: List of undefined behaviour and other sneeky bugs Jens Gustedt <jens.gustedt@loria.fr> - 2012-05-03 23:18 +0200
        Re: List of undefined behaviour and other sneeky bugs Keith Thompson <kst-u@mib.org> - 2012-05-03 15:58 -0700
    Re: List of undefined behaviour and other sneeky bugs pete <pfiland@mindspring.com> - 2012-05-04 00:25 -0400
      Re: List of undefined behaviour and other sneeky bugs John Reye <jononanon@googlemail.com> - 2012-05-03 22:28 -0700
        Re: List of undefined behaviour and other sneeky bugs James Kuyper <jameskuyper@verizon.net> - 2012-05-04 07:33 -0400
          Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 19:20 -0700
        Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 18:50 -0700
      Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 18:42 -0700
        Re: List of undefined behaviour and other sneeky bugs pete <pfiland@mindspring.com> - 2012-05-07 23:45 -0400
          Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-07 23:01 -0700
            Re: List of undefined behaviour and other sneeky bugs pete <pfiland@mindspring.com> - 2012-05-08 06:28 -0400
              Re: List of undefined behaviour and other sneeky bugs pete <pfiland@mindspring.com> - 2012-05-08 06:37 -0400
                Re: List of undefined behaviour and other sneeky bugs Tim Rentsch <txr@alumni.caltech.edu> - 2012-05-08 06:19 -0700

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#20369

FromNobody <nobody@nowhere.com>
Date2012-05-04 01:47 +0100
Message-ID<pan.2012.05.04.00.47.07.390000@nowhere.com>
In reply to#20330
On Thu, 03 May 2012 19:19:40 +0000, Jens Thoms Toerring wrote:

>> Well yes, because there are machines with different endianness.
> 
>> But I can get around that quite easy like this:

>> #ifdef LITTLE_ENDIAN

>> #else

You forgot the "PDP-endian" case: 16-bit values are stored as
low-byte followed by high-byte, while 32-bit values are stored as
high-word followed by low-word (i.e. 0x01020304 is stored as
0x0102,0x0304 which is stored as 0x02,0x01,0x04,0x03).

For a 4-byte value, there are 24 possible permutations, and a conforming
implementation could use any of them.

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


#20478

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-07 17:47 -0700
Message-ID<kfn4nrrzefb.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20309
John Reye <jononanon@googlemail.com> writes:

> Thanks for the warning about sizeof!! I missed that.
>
> On May 3, 7:38 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
>> > Or:
>> >                   struct
>> >                   {
>> >                      char a;
>> >                      union {
>> >                         int  b;
>> >                         char c;
>> >                      };
>> >                   } mystruct;
>> >                   mystruct.c = 0x12
>> > Would this union work on every platform??
>>
>> Yes. But the you won't be able to use the 'b' element of
>> the union since reading a different member than has been
>> set the last time round also invokes undefined behavior.
>
> Oh no, please no. Why on earth would that be undefined behaviour?
> [snip]

It isn't.  On platforms that have trap representations
it is possible for undefined behavior to arise, but
that's because of reading a trap representation, not
because of reading a union member other than the last
one set.

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


#20477

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-07 17:45 -0700
Message-ID<kfn8vh3zejr.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20306
jt@toerring.de (Jens Thoms Toerring) writes:

> John Reye <jononanon@googlemail.com> wrote:
>[snip]
>> Or:
>>                   struct
>>                   {
>>                      char a;
>>                      union {
>>                         int  b;
>>                         char c;
>>                      };
>>                   } mystruct;
>>                   mystruct.c = 0x12
>
>> Would this union work on every platform??
>
> Yes. But the you won't be able to use the 'b' element of
> the union since reading a different member than has been
> set the last time round also invokes undefined behavior.

That's wrong.  Reading a member other than the last member
set has defined behavior.  In cases where the member read
has a size larger than the last member set (as is the case
here), the value read depends on unspecified values in
some bytes.  If those unspecified values cause the object
representation for the type in question to be a trap
representation, then that will cause undefined behavior.
But simply reading a member other than the last member
set is not in and of itself undefined behavior.  And the
usual case, ie, reading a member whose size is no larger
than that of the member set, commonly has well-defined
and sometimes useful behavior.

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


#20493

Fromnick_keighley_nospam@hotmail.com
Date2012-05-08 00:43 -0700
Message-ID<28029579.3276.1336463009075.JavaMail.geo-discussion-forums@vbbgl4>
In reply to#20477
On Tuesday, May 8, 2012 1:45:12 AM UTC+1, Tim Rentsch wrote:
> jt@toerring.de (Jens Thoms Toerring) writes:
> 
> > John Reye <jononanon@googlemail.com> wrote:
> >[snip]
> >> Or:
> >>                   struct
> >>                   {
> >>                      char a;
> >>                      union {
> >>                         int  b;
> >>                         char c;
> >>                      };
> >>                   } mystruct;
> >>                   mystruct.c = 0x12
> >
> >> Would this union work on every platform??
> >
> > Yes. But the you won't be able to use the 'b' element of
> > the union since reading a different member than has been
> > set the last time round also invokes undefined behavior.
> 
> That's wrong.  Reading a member other than the last member
> set has defined behavior.  In cases where the member read
> has a size larger than the last member set (as is the case
> here), the value read depends on unspecified values in
> some bytes.  If those unspecified values cause the object
> representation for the type in question to be a trap
> representation, then that will cause undefined behavior.
> But simply reading a member other than the last member
> set is not in and of itself undefined behavior.  And the
> usual case, ie, reading a member whose size is no larger
> than that of the member set, commonly has well-defined
> and sometimes useful behavior.

but it is implementation defined so you can't, in general, predict what value you'll get

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


#20507

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-08 06:17 -0700
Message-ID<kfnk40mx15g.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20493
nick_keighley_nospam@hotmail.com writes:

> On Tuesday, May 8, 2012 1:45:12 AM UTC+1, Tim Rentsch wrote:
>> jt@toerring.de (Jens Thoms Toerring) writes:
>> 
>> > John Reye <jononanon@googlemail.com> wrote:
>> >[snip]
>> >> Or:
>> >>                   struct
>> >>                   {
>> >>                      char a;
>> >>                      union {
>> >>                         int  b;
>> >>                         char c;
>> >>                      };
>> >>                   } mystruct;
>> >>                   mystruct.c = 0x12
>> >
>> >> Would this union work on every platform??
>> >
>> > Yes. But the you won't be able to use the 'b' element of
>> > the union since reading a different member than has been
>> > set the last time round also invokes undefined behavior.
>> 
>> That's wrong.  Reading a member other than the last member
>> set has defined behavior.  In cases where the member read
>> has a size larger than the last member set (as is the case
>> here), the value read depends on unspecified values in
>> some bytes.  If those unspecified values cause the object
>> representation for the type in question to be a trap
>> representation, then that will cause undefined behavior.
>> But simply reading a member other than the last member
>> set is not in and of itself undefined behavior.  And the
>> usual case, ie, reading a member whose size is no larger
>> than that of the member set, commonly has well-defined
>> and sometimes useful behavior.
>
> but it is implementation defined so you can't, in general,
> predict what value you'll get

Neither C11 nor C99 use 'implementation-defined' in the
description of union member access.  The C90/C89 standard does
use this phrase;  however, what was meant, and what was generally
understood by implementors, is that the result is defined (ie, as
reinterpreting the underlying bits in the new representation) but
depends on other implementation-defined choices, the most obvious
of which is how different types are represented.  I suppose it is
possible, even though very unlikely, that some implementors of
very old compilers took advantage of the 'implementation-defined'
stipulation in C90 to do something unexpected here.  Do you have
any experience that suggests such implementations actually exist?
Unless there is one such otherwise-conforming implementation that
someone can point to, I don't think it's wrong to say the behavior
is defined even under C90;  certainly it is right under both C99
and the current C11 standard.

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


#20338

FromKeith Thompson <kst-u@mib.org>
Date2012-05-03 12:46 -0700
Message-ID<lnobq5nj2o.fsf@nuthaus.mib.org>
In reply to#20303
John Reye <jononanon@googlemail.com> writes:
[...]
>                   struct
>                   {
>                      char a;
>                      union {
>                         int  b;
>                         char c;
>                      };
>                   } mystruct;
>                   mystruct.c = 0x12
>
> Would this union work on every platform??

You have an unnamed union.  Some compilers support this as an extension,
but it's not valid in standard C.

You can fix it like this:

    struct {
        char a;
        union {
            int  b;
            char c;
        } u;
    } mystruct;
    mystruct.u.c = 0x12;

Note that you have to refer to mystruct.u.c, not mystruct.c, since c is
a member of a union which is a member of a struct.

As for whether it "works", that depends on what you want it to do.  It
stores the value 0x12 in mystruct.u.c, which is also the first byte of
mystruct.u.b.  If you access the first byte of mystruct.u.b,
*(char*)&mystruct.u.b, you'll get 0x12.  If you access mystruct.u.b as
an int, you'll get garbage, possibly a trap representation.

I can't think of anything useful you could do with this.  If you want to
access the char value you just stored, you can refer to mystruct.u.c.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#20344

FromJohn Reye <jononanon@googlemail.com>
Date2012-05-03 13:35 -0700
Message-ID<c42bba9a-5395-420a-abcb-5bdbc248e780@cl4g2000vbb.googlegroups.com>
In reply to#20338
On May 3, 9:46 pm, Keith Thompson <ks...@mib.org> wrote:
> As for whether it "works", that depends on what you want it to do.  It
> stores the value 0x12 in mystruct.u.c, which is also the first byte of
> mystruct.u.b.  If you access the first byte of mystruct.u.b,
> *(char*)&mystruct.u.b, you'll get 0x12.  If you access mystruct.u.b as
> an int, you'll get garbage, possibly a trap representation.
Will I really get garbage? I think not. The lowest-addressed byte is
0x12, and the other bytes of mystruct.u.b are what they were before,
right?
A trap? How can that possibly be justified? Why does the C language
have unions then? What is the intended use of unions?

Thanks

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


#20349

FromBen Pfaff <blp@cs.stanford.edu>
Date2012-05-03 14:05 -0700
Message-ID<87pqalnffh.fsf@blp.benpfaff.org>
In reply to#20344
John Reye <jononanon@googlemail.com> writes:

> Why does the C language have unions then? What is the intended
> use of unions?

"Tagged" unions are useful for, among other purposes,
constructing trees in which different nodes may contain different
data.

enum node_type {
        /* Terminal. */
        INT,
        REAL,

        /* Nonterminal. */
        ADD,
        SUB,
        MUL,
        DIV
};

struct node {
        enum node_type type;
        union {
                int integer;                 /* INT */
                double real;                 /* REAL */
                struct node *children[2];    /* ADD, SUB, MUL, DIV */
        } u;
};

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


#20352

FromJohn Reye <jononanon@googlemail.com>
Date2012-05-03 14:11 -0700
Message-ID<fc405a25-cfaf-4c4d-926d-1084ead31d34@n1g2000vby.googlegroups.com>
In reply to#20349
On May 3, 11:05 pm, Ben Pfaff <b...@cs.stanford.edu> wrote:
> John Reye <jonona...@googlemail.com> writes:
> > Why does the C language have unions then? What is the intended
> > use of unions?
>
> "Tagged" unions are useful for, among other purposes,
> constructing trees in which different nodes may contain different
> data.
>
> enum node_type {
>         /* Terminal. */
>         INT,
>         REAL,
>
>         /* Nonterminal. */
>         ADD,
>         SUB,
>         MUL,
>         DIV
>
> };
>
> struct node {
>         enum node_type type;
>         union {
>                 int integer;                 /* INT */
>                 double real;                 /* REAL */
>                 struct node *children[2];    /* ADD, SUB, MUL, DIV */
>         } u;
>
>
>
>
>
>
>
> };

So if you use a particular union access member... for a particular
union in memory, then you should always access that particular union-
variable, with the same member?

Is that the only intended use?

In particular: is it a misuse of unions, to use them in order to
enable different memory-accesses (word, byte, etc.) to the same
portion of memory???? I have (mis)used it like this in above posts
quite often.
Is that strictly wrong?

Thanks.

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


#20359

FromBen Pfaff <blp@cs.stanford.edu>
Date2012-05-03 15:02 -0700
Message-ID<87havworda.fsf@blp.benpfaff.org>
In reply to#20352
John Reye <jononanon@googlemail.com> writes:

> On May 3, 11:05 pm, Ben Pfaff <b...@cs.stanford.edu> wrote:
> So if you use a particular union access member... for a particular
> union in memory, then you should always access that particular union-
> variable, with the same member?
>
> Is that the only intended use?

I believe that is the intention.  I couldn't find relevant text
in the Rationale.

> In particular: is it a misuse of unions, to use them in order to
> enable different memory-accesses (word, byte, etc.) to the same
> portion of memory???? I have (mis)used it like this in above posts
> quite often.
> Is that strictly wrong?

I think there might be an "out" for accessing any type as an
array of unsigned char this way, but I believe that in general
this is strictly wrong.

I use "memcpy" to achieve a similar effect.

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


#20480

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-07 18:10 -0700
Message-ID<kfnvck7xyst.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20359
Ben Pfaff <blp@cs.stanford.edu> writes:

> John Reye <jononanon@googlemail.com> writes:
>
>> On May 3, 11:05 pm, Ben Pfaff <b...@cs.stanford.edu> wrote:
>> So if you use a particular union access member... for a particular
>> union in memory, then you should always access that particular union-
>> variable, with the same member?
>>
>> Is that the only intended use?
>
> I believe that is the intention.  I couldn't find relevant text
> in the Rationale.

If you read the Defect Report (sorry, I don't know the
number offhand) that prompted the famous "type punning"
footnote, I think you'll find that the type punning use
cases were expected and intended all along, eg, even in
C89/C90.  I presume they were important to make defined
because a significant amount of pre-ANSI C code relied
on them working.


>> In particular: is it a misuse of unions, to use them in order to
>> enable different memory-accesses (word, byte, etc.) to the same
>> portion of memory???? I have (mis)used it like this in above posts
>> quite often.
>> Is that strictly wrong?
>
> I think there might be an "out" for accessing any type as an
> array of unsigned char this way, but I believe that in general
> this is strictly wrong.  [snip]

How do you reconcile this view with the statement in
clear and plain English about how union member access
works to accomplish type punning?  I think anyone who
takes the time to read through the relevant sections
defining the semantics involved will find accessing a
union member is defined irrespective of which member
was last set (although the result may depend on
unspecified values and consequently undefined behavior
because of trap representations, but the access itself
is well-defined).

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


#20495

Fromnick_keighley_nospam@hotmail.com
Date2012-05-08 00:49 -0700
Message-ID<3688094.2254.1336463345478.JavaMail.geo-discussion-forums@vbki8>
In reply to#20480
On Tuesday, May 8, 2012 2:10:42 AM UTC+1, Tim Rentsch wrote:
> Ben Pfaff <blp@cs.stanford.edu> writes:
> 
> > John Reye <jononanon@googlemail.com> writes:
> >
> >> On May 3, 11:05 pm, Ben Pfaff <b...@cs.stanford.edu> wrote:
> >> So if you use a particular union access member... for a particular
> >> union in memory, then you should always access that particular union-
> >> variable, with the same member?
> >>
> >> Is that the only intended use?
> >
> > I believe that is the intention.  I couldn't find relevant text
> > in the Rationale.
> 
> If you read the Defect Report (sorry, I don't know the
> number offhand) that prompted the famous "type punning"
> footnote, I think you'll find that the type punning use
> cases were expected and intended all along, eg, even in
> C89/C90.  I presume they were important to make defined
> because a significant amount of pre-ANSI C code relied
> on them working.
> 
> 
> >> In particular: is it a misuse of unions, to use them in order to
> >> enable different memory-accesses (word, byte, etc.) to the same
> >> portion of memory???? I have (mis)used it like this in above posts
> >> quite often.
> >> Is that strictly wrong?
> >
> > I think there might be an "out" for accessing any type as an
> > array of unsigned char this way, but I believe that in general
> > this is strictly wrong.  [snip]
> 
> How do you reconcile this view with the statement in
> clear and plain English about how union member access
> works to accomplish type punning?  I think anyone who
> takes the time to read through the relevant sections
> defining the semantics involved will find accessing a
> union member is defined irrespective of which member
> was last set (although the result may depend on
> unspecified values and consequently undefined behavior
> because of trap representations, but the access itself
> is well-defined).

********************************
Draft ANSI Standard

3.3.2.3 Structure and union members
[...]
Semantics
[... 3rd para]
   With one exception, if a member of a union object is accessed after
a value has been stored in a different member of the object, the
behavior is implementation-defined./33/ One special guarantee is made
in order to simplify the use of unions: If a union contains several
structures that share a common initial sequence, and if the union
object currently contains one of these structures, it is permitted to
inspect the common initial part of any of them.  Two structures share
a common initial sequence if corresponding members have compatible
types for a sequence of one or more initial members.
********************

I don't think "implementation defined" is the same as well defined. They could return zero every time if they wanted.


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


#20498

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-05-08 06:37 -0400
Message-ID<joat0r$q3a$1@dont-email.me>
In reply to#20495
On 05/08/2012 03:49 AM, nick_keighley_nospam@hotmail.com wrote:
> On Tuesday, May 8, 2012 2:10:42 AM UTC+1, Tim Rentsch wrote:
>> Ben Pfaff <blp@cs.stanford.edu> writes:
...
>> If you read the Defect Report (sorry, I don't know the
>> number offhand) that prompted the famous "type punning"
>> footnote, I think you'll find that the type punning use
>> cases were expected and intended all along, eg, even in
>> C89/C90.  I presume they were important to make defined
>> because a significant amount of pre-ANSI C code relied
>> on them working.
...
>> How do you reconcile this view with the statement in
>> clear and plain English about how union member access
>> works to accomplish type punning?  I think anyone who
>> takes the time to read through the relevant sections
>> defining the semantics involved will find accessing a
>> union member is defined irrespective of which member
>> was last set (although the result may depend on
>> unspecified values and consequently undefined behavior
>> because of trap representations, but the access itself
>> is well-defined).
> 
> ********************************
> Draft ANSI Standard
> 
> 3.3.2.3 Structure and union members
> [...]
> Semantics
> [... 3rd para]
>    With one exception, if a member of a union object is accessed after
> a value has been stored in a different member of the object, the
> behavior is implementation-defined./33/ One special guarantee is made
> in order to simplify the use of unions: If a union contains several
> structures that share a common initial sequence, and if the union
> object currently contains one of these structures, it is permitted to
> inspect the common initial part of any of them.  Two structures share
> a common initial sequence if corresponding members have compatible
> types for a sequence of one or more initial members.
> ********************
> 
> I don't think "implementation defined" is the same as well defined. They could return zero every time if they wanted.

This is the "famous type-punning footnote" he referred to. It's footnote
95 in n1570.pdf:
"If the member used to read the contents of a union object is not the
same as the member last used to store a value in the object, the
appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as described
in 6.2.6 (a process sometimes called ‘‘type punning’’)."

Footnotes are informative, not normative. Informative text is supposed
to explain implications of what the normative text says, but if the
normative text does not actually imply what the footnote says it does,
the footnote is just plain wrong. The standard does not describe this
reinterpretation or type punning anywhere in the normative text.
Footnote 95 seems to be suggesting that this is a conclusion that can be
reached from the combination of what it says in 6.5.2.3p3 about the
semantics of the member selection operator, and what it says in 6.2.6
about the representations of types. It's not clear to me that this is
actually the case.

However, as a practical matter, footnote 95 documents what essentially
all implementations of C have always done, and will continue to do, when
translating such code. It unambiguously reflects the intent of the
committee, whether or not that intent has actually been clearly
expressed in the normative text of the standard. I think a programmer
who relies upon footnote 95 as if it were, in fact, a correct summary of
the normative text will never run into any trouble by reason of doing so.
-- 
James Kuyper

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


#20513

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-08 07:49 -0700
Message-ID<kfn397awwvu.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20498
James Kuyper <jameskuyper@verizon.net> writes:

[snip]

> Footnote 95 seems to be suggesting that this is a conclusion that
> can be reached from the combination of what it says in 6.5.2.3p3
> about the semantics of the member selection operator, and what it
> says in 6.2.6 about the representations of types. It's not clear to
> me that this is actually the case.

For those who are interested, it isn't hard to verify that the
normative text in C99/C11 supports what this footnote says in
informative text.  A previous posting of mine (posted, IIANM, in
January of this year) listed the relevant sections or paragraphs
that contribute to that.  I guess JK didn't see that since
apparently he routinely does not read my postings.

> However, as a practical matter, footnote 95 documents what
> essentially all implementations of C have always done, and will
> continue to do, when translating such code. It unambiguously
> reflects the intent of the committee, whether or not that intent
> has actually been clearly expressed in the normative text of the
> standard. I think a programmer who relies upon footnote 95 as if
> it were, in fact, a correct summary of the normative text will
> never run into any trouble by reason of doing so.

Ditto.

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


#20511

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-08 07:25 -0700
Message-ID<kfn7gwmwxzj.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20495
nick_keighley_nospam@hotmail.com writes:

> On Tuesday, May 8, 2012 2:10:42 AM UTC+1, Tim Rentsch wrote:
>> Ben Pfaff <blp@cs.stanford.edu> writes:
>> 
>> > John Reye <jononanon@googlemail.com> writes:
>> >
>> >> On May 3, 11:05 pm, Ben Pfaff <b...@cs.stanford.edu> wrote:
>> >> So if you use a particular union access member... for a particular
>> >> union in memory, then you should always access that particular union-
>> >> variable, with the same member?
>> >>
>> >> Is that the only intended use?
>> >
>> > I believe that is the intention.  I couldn't find relevant text
>> > in the Rationale.
>> 
>> If you read the Defect Report (sorry, I don't know the
>> number offhand) that prompted the famous "type punning"
>> footnote, I think you'll find that the type punning use
>> cases were expected and intended all along, eg, even in
>> C89/C90.  I presume they were important to make defined
>> because a significant amount of pre-ANSI C code relied
>> on them working.
>> 
>> 
>> >> In particular: is it a misuse of unions, to use them in order to
>> >> enable different memory-accesses (word, byte, etc.) to the same
>> >> portion of memory???? I have (mis)used it like this in above posts
>> >> quite often.
>> >> Is that strictly wrong?
>> >
>> > I think there might be an "out" for accessing any type as an
>> > array of unsigned char this way, but I believe that in general
>> > this is strictly wrong.  [snip]
>> 
>> How do you reconcile this view with the statement in
>> clear and plain English about how union member access
>> works to accomplish type punning?  I think anyone who
>> takes the time to read through the relevant sections
>> defining the semantics involved will find accessing a
>> union member is defined irrespective of which member
>> was last set (although the result may depend on
>> unspecified values and consequently undefined behavior
>> because of trap representations, but the access itself
>> is well-defined).
>
> ********************************
> Draft ANSI Standard
>
> 3.3.2.3 Structure and union members
> [...]
> Semantics
> [... 3rd para]
>    With one exception, if a member of a union object is accessed after
> a value has been stored in a different member of the object, the
> behavior is implementation-defined./33/ One special guarantee is made
> in order to simplify the use of unions: If a union contains several
> structures that share a common initial sequence, and if the union
> object currently contains one of these structures, it is permitted to
> inspect the common initial part of any of them.  Two structures share
> a common initial sequence if corresponding members have compatible
> types for a sequence of one or more initial members.
> ********************

This text corresponds to 6.3.2.3, fifth paragraph, in C90.  The
footnote /33/ referenced above is footnote 41 in the C90 document.
That footnote says:

   The ``byte orders'' for scalar types are invisible to isolated
   programs that do not indulge in type punning (for example, by
   assigning to one member of a union and inspecting the storage
   by accessing another member that is an appropropriately sized
   array of character type), but must be accounted for when
   conforming to externally imposed storage layouts.

> I don't think "implementation defined" is the same as well
> defined. They could return zero every time if they wanted.

I think the footnote makes it clear that the intention of the
'implementation-defined' wording is to reinterpret the underlying
bytes in the new type.  (Note that the quoted paragraph does
not exclude character types from the 'implementation-defined'
category.)  This view is also supported by DR 283 (I was able
to find it, fortunately easily, by "defect report" "type punning"
as a google query)

   http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm

which says in part (and written by someone on the committee)

   It is not perfectly clear that the C99 words have the same
   implications as the C89 words.

So even though C89/C90 says 'implementation-defined' and C99
doesn't, the indications are that the meaning intended is the
same in both cases, and also C11, which uses the same wording
as C99.  (There are minor changes in the C11 footnote relative
to N1256, but these are incidental.)

Summing up - I think you're right in some technical sense that
the C90 allowed returning zero every time.  But that isn't what
was intended, nor AFAIAA what any implementor took it to mean.
Unless there is a particular existing implementation that can be
pointed to that exhibits the problem, the point seems moot;
surely no current implementation would do anything other than
follow the revised wording in C99 or C11.

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


#20514

FromBen Pfaff <blp@cs.stanford.edu>
Date2012-05-08 09:46 -0700
Message-ID<87pqae1uyz.fsf@blp.benpfaff.org>
In reply to#20480
Tim Rentsch <txr@alumni.caltech.edu> writes:

> Ben Pfaff <blp@cs.stanford.edu> writes:
>
>> John Reye <jononanon@googlemail.com> writes:
>>
>>> On May 3, 11:05 pm, Ben Pfaff <b...@cs.stanford.edu> wrote:
>>> So if you use a particular union access member... for a particular
>>> union in memory, then you should always access that particular union-
>>> variable, with the same member?
>>>
>>> Is that the only intended use?
>>
>> I believe that is the intention.  I couldn't find relevant text
>> in the Rationale.
>
> If you read the Defect Report (sorry, I don't know the
> number offhand) that prompted the famous "type punning"
> footnote, I think you'll find that the type punning use
> cases were expected and intended all along, eg, even in
> C89/C90.  I presume they were important to make defined
> because a significant amount of pre-ANSI C code relied
> on them working.

Either I didn't know about that defect report or I'd forgotten
it.  Thanks for the correction.

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


#20361

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-05-03 18:24 -0400
Message-ID<4FA3058E.8090601@verizon.net>
In reply to#20352
On 05/03/2012 05:11 PM, John Reye wrote:
...
> So if you use a particular union access member... for a particular
> union in memory, then you should always access that particular union-
> variable, with the same member?
> 
> Is that the only intended use?

Not quite. In C99, the standard was changed to describe how essentially
all real-world implementations handled unions. Reading a different
member than the last one written now sometimes has defined behavior, so
long as it's not a trap representation. Specifically, it results in
reinterpretation of the bits that were set by the write, in accordance
with the representation for the member being read. Since the standard
gives implementations a great deal of freedom with how values of
different types are represented, code which takes advantage of that fact
can never be portable. However, if you're willing to restrict the
portability of your code to platforms where the relevant types are
represented the way that your code assumes they are represented, it
could be useful code - for those platforms.

> In particular: is it a misuse of unions, to use them in order to
> enable different memory-accesses (word, byte, etc.) to the same
> portion of memory???? I have (mis)used it like this in above posts
> quite often.
> Is that strictly wrong?

Whenever you read a member that is larger than the last one written to,
the bytes that are not part of of the smaller member will have
unspecified values. In that case, it's not sufficient to know how the
different types are represented on this particular implementation of C.
You'll also need to know precisely what that particular compiler does
with such code. The portability of such code is correspondingly more
restricted.


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


#20481

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-07 18:24 -0700
Message-ID<kfnr4uvxy6j.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20361
James Kuyper <jameskuyper@verizon.net> writes:

> On 05/03/2012 05:11 PM, John Reye wrote:
> ...
>> So if you use a particular union access member... for a particular
>> union in memory, then you should always access that particular union-
>> variable, with the same member?
>> 
>> Is that the only intended use?
>
> Not quite. In C99, the standard was changed to describe how essentially
> all real-world implementations handled unions.

I believe this statement is a mispreresentation of the actual
history;  a more accurate statement is that the wording was
changed but the intended behavior remained the same.  There
is evidence for this view in the Defect Report that prompted
the footnote accompanying 6.5.2.3 p3 (which is currently #95
in N1570, but the footnote was also present in N1256, #82).

> Reading a different
> member than the last one written now sometimes has defined behavior, so
> long as it's not a trap representation. Specifically, it results in
> reinterpretation of the bits that were set by the write, in accordance
> with the representation for the member being read. Since the standard
> gives implementations a great deal of freedom with how values of
> different types are represented, code which takes advantage of that fact
> can never be portable. However, if you're willing to restrict the
> portability of your code to platforms where the relevant types are
> represented the way that your code assumes they are represented, it
> could be useful code - for those platforms.

And there are some signifcant cases where the representations
are guaranteed to match, regardless of platform.


>> In particular: is it a misuse of unions, to use them in order to
>> enable different memory-accesses (word, byte, etc.) to the same
>> portion of memory???? I have (mis)used it like this in above posts
>> quite often.
>> Is that strictly wrong?
>
> Whenever you read a member that is larger than the last one written to,
> the bytes that are not part of of the smaller member will have
> unspecified values. In that case, it's not sufficient to know how the
> different types are represented on this particular implementation of C.
> You'll also need to know precisely what that particular compiler does
> with such code. The portability of such code is correspondingly more
> restricted.

That's right, and another important case might be mentioned.
If the value written was a struct, then any padding bytes
of the struct (and padding bits, presumably) take unspecified
values.  So unless what is being read matches up with (or
is a subset of) one of the members of the struct type written,
the same advisories about unspecified values and compiler
dependency apply.

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


#20354

Fromjt@toerring.de (Jens Thoms Toerring)
Date2012-05-03 21:17 +0000
Message-ID<a0gav5Fg6kU1@mid.uni-berlin.de>
In reply to#20344
John Reye <jononanon@googlemail.com> wrote:
> On May 3, 9:46 pm, Keith Thompson <ks...@mib.org> wrote:
> > As for whether it "works", that depends on what you want it to do.  It
> > stores the value 0x12 in mystruct.u.c, which is also the first byte of
> > mystruct.u.b.  If you access the first byte of mystruct.u.b,
> > *(char*)&mystruct.u.b, you'll get 0x12.  If you access mystruct.u.b as
> > an int, you'll get garbage, possibly a trap representation.

> Will I really get garbage? I think not. The lowest-addressed byte is
> 0x12, and the other bytes of mystruct.u.b are what they were before,
> right?

As you have seen there are different architectures, having
different ways of representing e.g. an int - it can start
wtith the most significant bute at the lowest address or
with the least significant byte (or some other byte - the
C standard must be written in a way that it can be used
on all possible architectures). Thus when you change just
the byte at the lowest adress the value you get when you
read out the whole int can be different on different archi-
tectures.

What is meant when the C standard says that something is un-
defined is that it can't promise a certain outcome on all
possible architectures. Nothing more. Thus, if you want to
write a truely portable program you must avoid all kinds of
undefined behaviour. But if you write platform dependent
code and the platform defines what the C standard doesn't
it's completely fine to just use it, you just have to be
aware of that. Actually, without undefined behaviour you
wouldn't be able to write platform-dependent code, so it
would be impossible to e.g. write an operating system or
a device driver.

> A trap? How can that possibly be justified?

By the existence of machines with properties that may
seem unusual to you but for which probably good reasons
existed. The C standard can only mandate behaviour that
has a chance to be implemented on as many architectures
as possible - otherwise it would be impossible to write
a C compiler for them. So it's restricted to a smallest
common divder. And that's exactly one of the primary rea-
sons why C has been that successful and is still going
strong after 40 years - it's possible to have a C com-
piler for a supercomputer and for whatever system runs
a wrist-watch, a phone etc., and a program written in
standard C will run the same way on each of them.

> Why does the C language
> have unions then? What is the intended use of unions?

So that you can store values of different types in the
same location. But, of course, it hardly makes sense to
expect that after one has written a value of type A in-
to that location to be able to read something of a dif-
ferent type from it. Or do you often put a handkerchief
into a drawer and, when you open it again, it's a rabbit?

                            Regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de

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


#20482

FromTim Rentsch <txr@alumni.caltech.edu>
Date2012-05-07 18:28 -0700
Message-ID<kfnmx5jxxye.fsf@x-alumni2.alumni.caltech.edu>
In reply to#20354
jt@toerring.de (Jens Thoms Toerring) writes:

> John Reye <jononanon@googlemail.com> wrote:
> [snip]
>
>> Why does the C language
>> have unions then? What is the intended use of unions?
>
> So that you can store values of different types in the
> same location. But, of course, it hardly makes sense to
> expect that after one has written a value of type A in-
> to that location to be able to read something of a dif-
> ferent type from it. Or do you often put a handkerchief
> into a drawer and, when you open it again, it's a rabbit?

Besides the useful cases that are platform dependent,
there are also cases where the same representation
is guaranteed between different types, on all platforms.

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


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

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


csiph-web