[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Casting between struct pointers

Barry Briggs

8/24/2011 3:45:00 PM

Hello,

I've tried to translate real code into something
small enough to discuss here. Hopefully, it still
makes some sense...

Consider the following.

Two unrelated structs:
struct desc { int a,b,c,d; };
struct pbuf { int e,f,g; };

A struct which "extends" 'struct pbuf':
struct pbuf2 { struct pbuf x; int y; };

And a struct that "binds" 'struct desc' and 'struct pbuf2':
struct foo { struct pbuf2 xx; struct desc yy; }

Finally consider a callback function
void callback_fun(struct pbuf *p)

At some point in my code, I have a 'struct foo' object,
(say struct foo toto)

I pass q = &toto.pbuf2.x (a struct pbuf pointer) to some
API function, and "sometime later" (threads involved)
the library will call callback_fun(q)

I need to "retrieve" toto.yy from callback_fun's parameter.

Is it safe to do
void callback_fun(struct pbuf *p)
{
struct foo *toto = (struct foo *)p;
/* use toto->desc */
}

considering that 'struct pbuf' is the first field of
'struct pbuf2', which is the first field of 'struct foo'?
Or am I in UB land?

Regards.
3 Answers

James Kuyper

8/24/2011 4:07:00 PM

0

On 08/24/2011 11:45 AM, Noob wrote:
> Hello,
>
> I've tried to translate real code into something
> small enough to discuss here. Hopefully, it still
> makes some sense...
>
> Consider the following.
>
> Two unrelated structs:
> struct desc { int a,b,c,d; };
> struct pbuf { int e,f,g; };
>
> A struct which "extends" 'struct pbuf':
> struct pbuf2 { struct pbuf x; int y; };
>
> And a struct that "binds" 'struct desc' and 'struct pbuf2':
> struct foo { struct pbuf2 xx; struct desc yy; }
>
> Finally consider a callback function
> void callback_fun(struct pbuf *p)
>
> At some point in my code, I have a 'struct foo' object,
> (say struct foo toto)
>
> I pass q = &toto.pbuf2.x (a struct pbuf pointer) to some

I'll assume that you meant &toto.xx.x?

> API function, and "sometime later" (threads involved)
> the library will call callback_fun(q)
>
> I need to "retrieve" toto.yy from callback_fun's parameter.
>
> Is it safe to do
> void callback_fun(struct pbuf *p)
> {
> struct foo *toto = (struct foo *)p;
> /* use toto->desc */
> }

Conversion of a pointer to the first member of a struct to the type of
the struct is guaranteed to produce a valid pointer to the containing
struct object. Therefore, it would be absolutely safe to do the following:

struct foo *toto = (struct foo*)(struct pbuf2*)p;

Technically, the standard does NOT guarantee that (struct foo*)(struct
pbuf2*) will produce the same result as a direct cast to (struct foo*).
However, in practice it should work.

Barry Briggs

8/31/2011 8:04:00 AM

0

James Kuyper wrote:
> On 08/24/2011 11:45 AM, Noob wrote:
>> Hello,
>>
>> I've tried to translate real code into something
>> small enough to discuss here. Hopefully, it still
>> makes some sense...
>>
>> Consider the following.
>>
>> Two unrelated structs:
>> struct desc { int a,b,c,d; };
>> struct pbuf { int e,f,g; };
>>
>> A struct which "extends" 'struct pbuf':
>> struct pbuf2 { struct pbuf x; int y; };
>>
>> And a struct that "binds" 'struct desc' and 'struct pbuf2':
>> struct foo { struct pbuf2 xx; struct desc yy; }
>>
>> Finally consider a callback function
>> void callback_fun(struct pbuf *p)
>>
>> At some point in my code, I have a 'struct foo' object,
>> (say struct foo toto)
>>
>> I pass q = &toto.pbuf2.x (a struct pbuf pointer) to some
>
> I'll assume that you meant &toto.xx.x?

You're right. I should have used simpler names, such as

struct pbuf2 { struct pbuf pbuf; int y; };
struct foo { struct pbuf2 pbuf2; struct desc desc; }

>> API function, and "sometime later" (threads involved)
>> the library will call callback_fun(q)
>>
>> I need to "retrieve" toto.yy from callback_fun's parameter.
>>
>> Is it safe to do
>> void callback_fun(struct pbuf *p)
>> {
>> struct foo *toto = (struct foo *)p;
>> /* use toto->desc */
>> }
>
> Conversion of a pointer to the first member of a struct to the type of
> the struct is guaranteed to produce a valid pointer to the containing
> struct object. Therefore, it would be absolutely safe to do the following:
>
> struct foo *toto = (struct foo*)(struct pbuf2*)p;

I never thought I would ever see a legitimate reason to write
two casts on the same line. I had always assumed that it would
be sufficient to have only the first cast, i.e. the final type.

> Technically, the standard does NOT guarantee that (struct foo*)(struct
> pbuf2*) will produce the same result as a direct cast to (struct foo*).
> However, in practice it should work.

I see.

Thanks for the detailed answer!

Regards.

Tim Rentsch

9/4/2011 8:08:00 PM

0

James Kuyper <jameskuyper@verizon.net> writes:

> On 08/24/2011 11:45 AM, Noob wrote:
>> Hello,
>>
>> I've tried to translate real code into something
>> small enough to discuss here. Hopefully, it still
>> makes some sense...
>>
>> Consider the following.
>>
>> Two unrelated structs:
>> struct desc { int a,b,c,d; };
>> struct pbuf { int e,f,g; };
>>
>> A struct which "extends" 'struct pbuf':
>> struct pbuf2 { struct pbuf x; int y; };
>>
>> And a struct that "binds" 'struct desc' and 'struct pbuf2':
>> struct foo { struct pbuf2 xx; struct desc yy; }
>>
>> Finally consider a callback function
>> void callback_fun(struct pbuf *p)
>>
>> At some point in my code, I have a 'struct foo' object,
>> (say struct foo toto)
>>
>> I pass q = &toto.pbuf2.x (a struct pbuf pointer) to some
>
> I'll assume that you meant &toto.xx.x?
>
>> API function, and "sometime later" (threads involved)
>> the library will call callback_fun(q)
>>
>> I need to "retrieve" toto.yy from callback_fun's parameter.
>>
>> Is it safe to do
>> void callback_fun(struct pbuf *p)
>> {
>> struct foo *toto = (struct foo *)p;
>> /* use toto->desc */
>> }
>
> Conversion of a pointer to the first member of a struct to the type of
> the struct is guaranteed to produce a valid pointer to the containing
> struct object. Therefore, it would be absolutely safe to do the following:
>
> struct foo *toto = (struct foo*)(struct pbuf2*)p;
>
> Technically, the standard does NOT guarantee that (struct foo*)(struct
> pbuf2*) will produce the same result as a direct cast to (struct foo*).
> However, in practice it should work.

It does provided you believe, as all sensible people do,
that all valid pointers (that aren't null) point to objects.