Casting between struct pointers

N

Noob

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

James Kuyper

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

Noob

James said:
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; }
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.
 
T

Tim Rentsch

James Kuyper said:
I'll assume that you meant &toto.xx.x?


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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top