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


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

Struct casting

Started byEdward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com>
First post2011-12-05 21:52 +0000
Last post2011-12-08 21:08 +0000
Articles 17 — 13 participants

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


Contents

  Struct casting Edward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com> - 2011-12-05 21:52 +0000
    Re: Struct casting Harald van Dijk <truedfx@gmail.com> - 2011-12-05 13:58 -0800
    Re: Struct casting Tobias Blass <tobiasblass@gmx.net> - 2011-12-05 22:00 +0000
      Re: Struct casting Ian Collins <ian-news@hotmail.com> - 2011-12-06 11:10 +1300
    Re: Struct casting tom st denis <tom@iahu.ca> - 2011-12-05 14:06 -0800
      Re: Struct casting Ian Collins <ian-news@hotmail.com> - 2011-12-06 11:11 +1300
      Re: Struct casting James Kuyper <jameskuyper@verizon.net> - 2011-12-05 17:13 -0500
    Re: Struct casting Robert Wessel <robertwessel2@yahoo.com> - 2011-12-05 16:10 -0600
      Re: Struct casting Ian Collins <ian-news@hotmail.com> - 2011-12-06 11:13 +1300
      Re: Struct casting James Kuyper <jameskuyper@verizon.net> - 2011-12-05 17:15 -0500
    Re: Struct casting Keith Thompson <kst-u@mib.org> - 2011-12-05 14:16 -0800
      Re: Struct casting Lauri Alanko <la@iki.fi> - 2011-12-06 18:00 +0000
    Re: Struct casting blp@cs.stanford.edu (Ben Pfaff) - 2011-12-05 14:19 -0800
    Re: Struct casting jacob navia <jacob@spamsink.net> - 2011-12-06 08:29 +0100
      Re: Struct casting Malcolm McLean <malcolm.mclean5@btinternet.com> - 2011-12-06 00:15 -0800
        Re: Struct casting Ian Collins <ian-news@hotmail.com> - 2011-12-06 22:30 +1300
    Re: Struct casting jgk@panix.com (Joe keane) - 2011-12-08 21:08 +0000

#14337 — Struct casting

FromEdward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com>
Date2011-12-05 21:52 +0000
SubjectStruct casting
Message-ID<jbjeed$c1v$1@speranza.aioe.org>
This was pulled up at a code review. Code was similar to this:

struct foo {
  int bar;
  int baz;
} f;

int * i = (int *) f;

The only way this could go wrong is if the struct contains padding before 
its first member, but I don't think this would ever happen in practice 
--- maybe on theoretical perverse implementations like the ones you guys 
like to play with :)

Who is right here by the letter of the law?

Cheers
Edward

[toc] | [next] | [standalone]


#14338

FromHarald van Dijk <truedfx@gmail.com>
Date2011-12-05 13:58 -0800
Message-ID<9b516a84-fba4-4fbd-80b4-657fec875a06@z17g2000vbe.googlegroups.com>
In reply to#14337
On Dec 5, 10:52 pm, Edward Rutherford
<edward.p.rutherfor...@REMOVETHIS.gmail.com> wrote:
> This was pulled up at a code review. Code was similar to this:
>
> struct foo {
>   int bar;
>   int baz;
>
> } f;

I'm assuming you meant } *f;

>
> int * i = (int *) f;

because otherwise this should be a hard error.

> The only way this could go wrong is if the struct contains padding before
> its first member, but I don't think this would ever happen in practice

A pointer to a struct can be safely converted to a pointer to its
first member, and back. Padding before the first member is not
allowed.

That said, for various other reasons, relating to readability and
maintainability, it may well be better to just write

  int *i = &f->bar;

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


#14339

FromTobias Blass <tobiasblass@gmx.net>
Date2011-12-05 22:00 +0000
Message-ID<jbjet4$dl3$1@dont-email.me>
In reply to#14337
On 2011-12-05, Edward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com> wrote:
> This was pulled up at a code review. Code was similar to this:
>
> struct foo {
>   int bar;
>   int baz;
> } f;
>
> int * i = (int *) f;
>
> The only way this could go wrong is if the struct contains padding before 
> its first member, but I don't think this would ever happen in practice 
> --- maybe on theoretical perverse implementations like the ones you guys 
> like to play with :)
>
> Who is right here by the letter of the law?
>
The standard guarantees that there is no padding before the first element, so
this conversion is absolutely valid. It may cause problems when another variable
is placed before the 'bar',though, and I wouldn't bet that the person that adds
the new member will change all these assignments.

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


#14341

FromIan Collins <ian-news@hotmail.com>
Date2011-12-06 11:10 +1300
Message-ID<9k4tqhF18rU1@mid.individual.net>
In reply to#14339
On 12/ 6/11 11:00 AM, Tobias Blass wrote:
> On 2011-12-05, Edward Rutherford<edward.p.rutherford79@REMOVETHIS.gmail.com>  wrote:
>> This was pulled up at a code review. Code was similar to this:
>>
>> struct foo {
>>    int bar;
>>    int baz;
>> } f;
>>
>> int * i = (int *) f;
>>
>> The only way this could go wrong is if the struct contains padding before
>> its first member, but I don't think this would ever happen in practice
>> --- maybe on theoretical perverse implementations like the ones you guys
>> like to play with :)
>>
>> Who is right here by the letter of the law?
>>
> The standard guarantees that there is no padding before the first element, so
> this conversion is absolutely valid.

Not as written.  There's a * in the declaration f or an & in the 
initialisation of i missing.

> It may cause problems when another variable
> is placed before the 'bar',though, and I wouldn't bet that the person that adds
> the new member will change all these assignments.

As mentioned else-thread,

int *i = &f->bar;

would be better.

-- 
Ian Collins

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


#14340

Fromtom st denis <tom@iahu.ca>
Date2011-12-05 14:06 -0800
Message-ID<1ff2e759-cf81-4eee-8278-50a3992fb7d9@x7g2000yqb.googlegroups.com>
In reply to#14337
On Dec 5, 4:52 pm, Edward Rutherford
<edward.p.rutherfor...@REMOVETHIS.gmail.com> wrote:
> This was pulled up at a code review. Code was similar to this:
>
> struct foo {
>   int bar;
>   int baz;
>
> } f;
>
> int * i = (int *) f;
>
> The only way this could go wrong is if the struct contains padding before
> its first member, but I don't think this would ever happen in practice
> --- maybe on theoretical perverse implementations like the ones you guys
> like to play with :)
>
> Who is right here by the letter of the law?

Is there a question of alignment though?

Generally, that sort of code would fail review with me and my cohorts
[er...coworkers].  If you wanted a specific element of a struct you
should pick it by name.

Tom

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


#14343

FromIan Collins <ian-news@hotmail.com>
Date2011-12-06 11:11 +1300
Message-ID<9k4trmF18rU2@mid.individual.net>
In reply to#14340
On 12/ 6/11 11:06 AM, tom st denis wrote:
> On Dec 5, 4:52 pm, Edward Rutherford
> <edward.p.rutherfor...@REMOVETHIS.gmail.com>  wrote:
>> This was pulled up at a code review. Code was similar to this:
>>
>> struct foo {
>>    int bar;
>>    int baz;
>>
>> } f;
>>
>> int * i = (int *) f;
>>
>> The only way this could go wrong is if the struct contains padding before
>> its first member, but I don't think this would ever happen in practice
>> --- maybe on theoretical perverse implementations like the ones you guys
>> like to play with :)
>>
>> Who is right here by the letter of the law?
>
> Is there a question of alignment though?

No.

-- 
Ian Collins

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


#14345

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-12-05 17:13 -0500
Message-ID<4EDD4217.6010900@verizon.net>
In reply to#14340
On 12/05/2011 05:06 PM, tom st denis wrote:
> On Dec 5, 4:52 pm, Edward Rutherford
> <edward.p.rutherfor...@REMOVETHIS.gmail.com> wrote:
>> This was pulled up at a code review. Code was similar to this:
>>
>> struct foo {
>>   int bar;
>>   int baz;
>>
>> } f;
>>
>> int * i = (int *) f;
>>
>> The only way this could go wrong is if the struct contains padding before
>> its first member, but I don't think this would ever happen in practice
>> --- maybe on theoretical perverse implementations like the ones you guys
>> like to play with :)
>>
>> Who is right here by the letter of the law?
> 
> Is there a question of alignment though?

No, there is not. The standard guarantees that conversion of a pointer
to a struct to a pointer to the type of the first member produces a
valid pointer to that first member.

> Generally, that sort of code would fail review with me and my cohorts
> [er...coworkers].  If you wanted a specific element of a struct you
> should pick it by name.

Agreed. In addition to protecting against the possibility that bar might
be moved to a different position, it's also more type-safe, since a type
cast is no longer necessary.

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


#14342

FromRobert Wessel <robertwessel2@yahoo.com>
Date2011-12-05 16:10 -0600
Message-ID<iufqd7l0lomlhch0hdich5psoepvvv5i6l@4ax.com>
In reply to#14337
On Mon, 5 Dec 2011 21:52:13 +0000 (UTC), Edward Rutherford
<edward.p.rutherford79@REMOVETHIS.gmail.com> wrote:

>This was pulled up at a code review. Code was similar to this:
>
>struct foo {
>  int bar;
>  int baz;
>} f;
>
>int * i = (int *) f;
>
>The only way this could go wrong is if the struct contains padding before 
>its first member, but I don't think this would ever happen in practice 
>--- maybe on theoretical perverse implementations like the ones you guys 
>like to play with :)
>
>Who is right here by the letter of the law?


FWIW, C++ compilers frequently put the vtable pointer at the beginning
of classes/structs that contain virtual functions (IOW, the "padding"
at the beginning of the struct would be the vtable pointer)..

In C, while two structures need to have the same layout in a common
leading area, I'm not sure there's a guarantee that the pointer to the
beginning of the beginning of the structure is required to be a
pointer to the first member.

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


#14344

FromIan Collins <ian-news@hotmail.com>
Date2011-12-06 11:13 +1300
Message-ID<9k4tvrF18rU3@mid.individual.net>
In reply to#14342
On 12/ 6/11 11:10 AM, Robert Wessel wrote:
> On Mon, 5 Dec 2011 21:52:13 +0000 (UTC), Edward Rutherford
> <edward.p.rutherford79@REMOVETHIS.gmail.com>  wrote:
>
>> This was pulled up at a code review. Code was similar to this:
>>
>> struct foo {
>>   int bar;
>>   int baz;
>> } f;
>>
>> int * i = (int *) f;
>>
>> The only way this could go wrong is if the struct contains padding before
>> its first member, but I don't think this would ever happen in practice
>> --- maybe on theoretical perverse implementations like the ones you guys
>> like to play with :)
>>
>> Who is right here by the letter of the law?
>
>
> FWIW, C++ compilers frequently put the vtable pointer at the beginning
> of classes/structs that contain virtual functions (IOW, the "padding"
> at the beginning of the struct would be the vtable pointer)..
>
> In C, while two structures need to have the same layout in a common
> leading area, I'm not sure there's a guarantee that the pointer to the
> beginning of the beginning of the structure is required to be a
> pointer to the first member.

There is.

-- 
Ian Collins

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


#14346

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-12-05 17:15 -0500
Message-ID<4EDD4269.8000502@verizon.net>
In reply to#14342
On 12/05/2011 05:10 PM, Robert Wessel wrote:
...
> In C, while two structures need to have the same layout in a common
> leading area, I'm not sure there's a guarantee that the pointer to the
> beginning of the beginning of the structure is required to be a
> pointer to the first member.

There is: 6.7.2.1p13.

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


#14347

FromKeith Thompson <kst-u@mib.org>
Date2011-12-05 14:16 -0800
Message-ID<lnsjkyll5i.fsf@nuthaus.mib.org>
In reply to#14337
Edward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com> writes:
> This was pulled up at a code review. Code was similar to this:
>
> struct foo {
>   int bar;
>   int baz;
> } f;
>
> int * i = (int *) f;

That should be

    int *i = (int*)&f;

> The only way this could go wrong is if the struct contains padding before 
> its first member, but I don't think this would ever happen in practice 
> --- maybe on theoretical perverse implementations like the ones you guys 
> like to play with :)

There cannot be any padding before the first member.  The code is safe,
but poor style.  Presumably the member "bar" was given a name for a
reason; just use that name:

    int *i = &f.bar;

Unless, for some odd reason, you specifically want the address of
the first member of the struct, and you're sure it's an int without
being sure of its name.

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


#14355

FromLauri Alanko <la@iki.fi>
Date2011-12-06 18:00 +0000
Message-ID<jbll7e$ram$1@oravannahka.helsinki.fi>
In reply to#14347
In article <lnsjkyll5i.fsf@nuthaus.mib.org>,
Keith Thompson  <kst-u@mib.org> wrote:
> There cannot be any padding before the first member.  The code is safe,
> but poor style.  Presumably the member "bar" was given a name for a
> reason; just use that name:
> 
>     int *i = &f.bar;
> 
> Unless, for some odd reason, you specifically want the address of
> the first member of the struct, and you're sure it's an int without
> being sure of its name.

It's a common idiom to simulate poor man's subtyping for structs by
placing the supertype struct as the first member of the subtype
struct, and then casting between struct pointer types. It may even be
that the members of the structs are hidden from client code (or at
least considered private), so the public interface might only say that
a subtype struct pointer can be cast to the supertype pointer (and
back again) without saying anything about the names of the members.

Then again, the direct address-of-member approach, along with a
containerof macro, gives you multiple inheritance, which might be
useful.


Lauri

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


#14348

Fromblp@cs.stanford.edu (Ben Pfaff)
Date2011-12-05 14:19 -0800
Message-ID<87wraahda8.fsf@blp.benpfaff.org>
In reply to#14337
Edward Rutherford <edward.p.rutherford79@REMOVETHIS.gmail.com> writes:

> Who is right here by the letter of the law?

Others already gave the answer.  Here's the quote from the
standard:

     A pointer to a structure object, suitably converted, points
     to its initial member (or if that member is a bit-field,
     then to the unit in which it resides), and vice versa.
-- 
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}

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


#14349

Fromjacob navia <jacob@spamsink.net>
Date2011-12-06 08:29 +0100
Message-ID<jbkg83$ad8$1@speranza.aioe.org>
In reply to#14337
Le 05/12/11 22:52, Edward Rutherford a écrit :
> This was pulled up at a code review. Code was similar to this:
>
> struct foo {
>    int bar;
>    int baz;
> } f;
>
> int * i = (int *) f;
>
> The only way this could go wrong is if the struct contains padding before
> its first member, but I don't think this would ever happen in practice
> --- maybe on theoretical perverse implementations like the ones you guys
> like to play with :)
>
> Who is right here by the letter of the law?
>
> Cheers
> Edward

This is a mistake. Instead of writing

int *i = &f.bar; // 16 characters

you write

int * i = (int *) f; // 20 characters

AND (most important):

Now, the "bar" member MUST be the first member of the
structure! And, as Murphy's Law states, sombody will
add a member to the struct foo in the new version,
2 years from here.

WHO will remember that in another file there was an
implicit dependency as to "bar" being the first member?

This code is unmaintainable, it provokes a bug if
ANY modification is done to "bar" within the structure.

Suppose that "bar" member is eliminated. Instead of
provokinbg a compiler error and forcing you to change
the dependent code, the code will silently compile
and provoke a VERY hard debugging session.

I see no justification whatsoever for writing code
like that.

jacob

P.S. Anyway your code doesn't compile, as others have said.

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


#14350

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2011-12-06 00:15 -0800
Message-ID<bebc7ea8-a1f8-48e9-b58c-dc669f6868bc@d10g2000vbf.googlegroups.com>
In reply to#14349
On Dec 6, 9:29 am, jacob navia <ja...@spamsink.net> wrote:
>
> int * i = (int *) f; // 20 characters
>
> I see no justification whatsoever for writing code
> like that.
>
As the snippet goes, no.

But "bar" might in fact be type a identifier field

foodoo(struct foo *f)
{
  switch( *( int *) f)
  {
     case REALLYABAR:
       dobar(f); return;
     case REALLYAFOO:
       dofoo(f); return;
  }
}

This is arguably better than switch(foo->bar) because it makes clear
that code will onyl work if the identifier is the first member.

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


#14351

FromIan Collins <ian-news@hotmail.com>
Date2011-12-06 22:30 +1300
Message-ID<9k65ksFuhiU2@mid.individual.net>
In reply to#14350
On 12/ 6/11 09:15 PM, Malcolm McLean wrote:
> On Dec 6, 9:29 am, jacob navia<ja...@spamsink.net>  wrote:
>>
>> int * i = (int *) f; // 20 characters
>>
>> I see no justification whatsoever for writing code
>> like that.
>>
> As the snippet goes, no.
>
> But "bar" might in fact be type a identifier field
>
> foodoo(struct foo *f)
> {
>    switch( *( int *) f)
>    {
>       case REALLYABAR:
>         dobar(f); return;
>       case REALLYAFOO:
>         dofoo(f); return;
>    }
> }
>
> This is arguably better than switch(foo->bar) because it makes clear
> that code will onyl work if the identifier is the first member.

Better still is to give the first member a name that identifies is as 
the type identifier field.  The X XEvent union is a good example of this.

-- 
Ian Collins

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


#14404

Fromjgk@panix.com (Joe keane)
Date2011-12-08 21:08 +0000
Message-ID<jbr8vg$3sb$1@reader1.panix.com>
In reply to#14337
In article <jbjeed$c1v$1@speranza.aioe.org>,
Edward Rutherford  <edward.p.rutherford79@REMOVETHIS.gmail.com> wrote:
>Who is right here by the letter of the law?

Letter of law, 'good idea' is often different.

It's right, but when someone comes along and mofidies your code,
is it likely to do what they expect?

Of course you put a comment that that member needs to be first, right?

[toc] | [prev] | [standalone]


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


csiph-web