![]() |
Questions about pointers to objects and pointers to functions
Hello,
I've got a few questions: 1) Given the two structs struct A { int x; }; and struct B { struct A y; int z; }; is it ok to treat a "pointer to an object of type struct B" as a "pointer to an object of type struct A"? (I think someone asked something like this some time ago, but unfortunately I can't find the article anymore) 2) When I now have a function pointer of type void (*fpa)(struct A *, int); and a function pointer of type void (*fpb)(struct B *, int); and the corresponding functions void fa(struct A*,int); and void fb(struct B*,int); is it ok to assign a "pointer to fa" to fpb and call the function through fpb with a "pointer to an object of type struct B" as the first parameter? Thanks in advance Marc Thrun |
Re: Questions about pointers to objects and pointers to functions
Marc Thrun <TekWarrior@gmx.de> wrote:
# Hello, # # I've got a few questions: # # 1) Given the two structs # struct A { # int x; # }; # # and # # struct B { # struct A y; # int z; # }; # # is it ok to treat a "pointer to an object of type struct B" as a # "pointer to an object of type struct A"? Given struct B sample you are guarenteed (struct A*)(&sample) == &(sample.y) that is, a pointer to a struct is also a pointer to the first field. -- SM Ryan http://www.rawbw.com/~wyrmwif/ Who's leading this mob? |
Re: Questions about pointers to objects and pointers to functions
Marc Thrun <TekWarrior@gmx.de> writes:
> Hello, > > I've got a few questions: > > 1) Given the two structs > struct A { > int x; > }; > > and > > struct B { > struct A y; > int z; > }; > > is it ok to treat a "pointer to an object of type struct B" as a > "pointer to an object of type struct A"? > (I think someone asked something like this some time ago, but > unfortunately I can't find the article anymore) This question might mean a couple of different things. If you're asking about converting (casting) a 'struct B *' to a 'struct A *' then that has to work, eg struct B *b = ...; struct A *a; a = (struct A*) b; if( a == &b->y ) /* this 'if' will always be taken */ You might be asking about converting the object representation directly, eg, with one of memcpy( &a, &b, sizeof a ); /* 1 */ a = * (struct A**) &b; /* 2 */ Either /*1*/ or /*2*/ should also result in a usable pointer that passes the 'if' test above. That is to say, to the best of my understanding that is how the language in the Standard should be understood. It's possible to debate the point; the language used in talking about such things is not completely clear cut. As a practical matter, however, it's reasonable to expect that this result will hold in any actual implementation. > 2) When I now have a function pointer of type > void (*fpa)(struct A *, int); > and a function pointer of type > void (*fpb)(struct B *, int); > > and the corresponding functions > void fa(struct A*,int); > and > void fb(struct B*,int); > > is it ok to assign a "pointer to fa" to fpb and call the function > through fpb with a "pointer to an object of type struct B" as the first > parameter? Technically such a call is illegal, since the two types are not compatible. But, even though it's technically illegal, it's almost certainly going to work in any actual implementation. |
Re: Questions about pointers to objects and pointers to functions
Tim Rentsch wrote:
> Marc Thrun <TekWarrior@gmx.de> writes: > > >>Hello, >> >>I've got a few questions: >> >>1) Given the two structs >>struct A { >> int x; >>}; >> >>and >> >>struct B { >> struct A y; >> int z; >>}; >> >>is it ok to treat a "pointer to an object of type struct B" as a >>"pointer to an object of type struct A"? >>(I think someone asked something like this some time ago, but >>unfortunately I can't find the article anymore) > > > This question might mean a couple of different things. If you're > asking about converting (casting) a 'struct B *' to a 'struct A *' > then that has to work, eg > I admit that it's quite a bit unclear, sorry for my not so good english ;-). But you are right, I meant casting (I just wonder why I did not take this term actually). > struct B *b = ...; > struct A *a; > > a = (struct A*) b; > if( a == &b->y ) /* this 'if' will always be taken */ > > You might be asking about converting the object representation > directly, eg, with one of > > memcpy( &a, &b, sizeof a ); /* 1 */ > > a = * (struct A**) &b; /* 2 */ > > Either /*1*/ or /*2*/ should also result in a usable pointer that > passes the 'if' test above. That is to say, to the best of my > understanding that is how the language in the Standard should be > understood. It's possible to debate the point; the language used > in talking about such things is not completely clear cut. As a > practical matter, however, it's reasonable to expect that this > result will hold in any actual implementation. > > > >>2) When I now have a function pointer of type >>void (*fpa)(struct A *, int); >>and a function pointer of type >>void (*fpb)(struct B *, int); >> >>and the corresponding functions >>void fa(struct A*,int); >>and >>void fb(struct B*,int); >> >>is it ok to assign a "pointer to fa" to fpb and call the function >>through fpb with a "pointer to an object of type struct B" as the first >>parameter? > > > Technically such a call is illegal, since the two types are not > compatible. But, even though it's technically illegal, it's > almost certainly going to work in any actual implementation. I thought the same, but was not sure. Assuming I would use a void * for the first parameter in both functions, and casting it to the type "struct A*"/"struct B*" should be valid then? PS: Where can I get a copy of the standard (maybe a draft version)? Might help me next time ;-). |
Re: Questions about pointers to objects and pointers to functions
Marc Thrun <TekWarrior@gmx.de> writes:
> Tim Rentsch wrote: > > Marc Thrun <TekWarrior@gmx.de> writes: [snip] > >>2) When I now have a function pointer of type > >>void (*fpa)(struct A *, int); > >>and a function pointer of type > >>void (*fpb)(struct B *, int); > >> > >>and the corresponding functions > >>void fa(struct A*,int); > >>and > >>void fb(struct B*,int); > >> > >>is it ok to assign a "pointer to fa" to fpb and call the function > >>through fpb with a "pointer to an object of type struct B" as the first > >>parameter? > > > > > > Technically such a call is illegal, since the two types are not > > compatible. But, even though it's technically illegal, it's > > almost certainly going to work in any actual implementation. > > I thought the same, but was not sure. Assuming I would use a void * for > the first parameter in both functions, and casting it to the type > "struct A*"/"struct B*" should be valid then? Using void fa( void *pv, int n ){ ... }; void fb( void *pv, int n ){ ... }; void (*fpa)( void *, int ) = fa; void (*fpb)( void *, int ) = fb; makes assignment of the function pointers, and also the resultant calls, legal. As you point out, it's then necessary to convert the void* parameters inside the actual function bodies to be of the appropriate type. If I were asked, I'd be inclined to recommend using the first approach (that uses 'struct A*' and 'struct B*' types, and not 'void*' types), because the stronger type checking done would be more likely to catch errors than some theoretical advantage that might result from using 'void*'. But that could depend on the local situation and what tradeoffs were considered important in the context of the particular project. > PS: Where can I get a copy of the standard (maybe a draft version)? > Might help me next time ;-). I'm sorry, I don't have a URL handy; if you do a google search I expect you'll find something without too much difficulty. |
Re: Questions about pointers to objects and pointers to functions
Tim Rentsch <txr@alumnus.caltech.edu> wrote:
> Marc Thrun <TekWarrior@gmx.de> writes: >> struct A { >> int x; >> }; >> >> and >> >> struct B { >> struct A y; >> int z; >> }; [snip] > > a = (struct A*) b; > if( a == &b->y ) /* this 'if' will always be taken */ > > You might be asking about converting the object representation > directly, eg, with one of > > memcpy( &a, &b, sizeof a ); /* 1 */ > > a = * (struct A**) &b; /* 2 */ > > Either /*1*/ or /*2*/ should also result in a usable pointer that > passes the 'if' test above. That is to say, to the best of my > understanding that is how the language in the Standard should be > understood. Generally, I agree, with a warning: /*2*/ is meant to express reinterpretation (wich is basically what /*1*/ does as well), but is technically UB (you're accessing the value of `b' with an incompatible type lvalue), and might cause real trouble in real world (esp. when compiler optimization is turned on). -- Stan Tobias mailx `echo siXtY@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g` |
Re: Questions about pointers to objects and pointers to functions
"S.Tobias" <siXtY@FamOuS.BedBuG.pAlS.INVALID> writes:
> Tim Rentsch <txr@alumnus.caltech.edu> wrote: > > Marc Thrun <TekWarrior@gmx.de> writes: > > >> struct A { > >> int x; > >> }; > >> > >> and > >> > >> struct B { > >> struct A y; > >> int z; > >> }; > [snip] > > > > a = (struct A*) b; > > if( a == &b->y ) /* this 'if' will always be taken */ > > > > You might be asking about converting the object representation > > directly, eg, with one of > > > > memcpy( &a, &b, sizeof a ); /* 1 */ > > > > a = * (struct A**) &b; /* 2 */ > > > > Either /*1*/ or /*2*/ should also result in a usable pointer that > > passes the 'if' test above. That is to say, to the best of my > > understanding that is how the language in the Standard should be > > understood. > > Generally, I agree, with a warning: /*2*/ is meant to express > reinterpretation (wich is basically what /*1*/ does as well), > but is technically UB (you're accessing the value of `b' with > an incompatible type lvalue), and might cause real trouble in > real world (esp. when compiler optimization is turned on). Right, both on the technical UB and on the real potential for problems. Thank you for pointing this out. Rather than /*2*/ we might consider /*2'*/: a = * (struct A *volatile *) &b; /* 2' */ Of course, this access still technically results in UB, but it's unlikely that the access here will result in any real world difficulties. |
Re: Questions about pointers to objects and pointers to functions
Tim Rentsch <txr@alumnus.caltech.edu> wrote:
> "S.Tobias" <siXtY@FamOuS.BedBuG.pAlS.INVALID> writes: > >> Tim Rentsch <txr@alumnus.caltech.edu> wrote: >> > Marc Thrun <TekWarrior@gmx.de> writes: >> >> >> struct A { >> >> int x; >> >> }; >> >> >> >> and >> >> >> >> struct B { >> >> struct A y; >> >> int z; >> >> }; >> [snip] >> > >> > a = (struct A*) b; >> > if( a == &b->y ) /* this 'if' will always be taken */ >> > >> > You might be asking about converting the object representation >> > directly, eg, with one of >> > >> > memcpy( &a, &b, sizeof a ); /* 1 */ >> > >> > a = * (struct A**) &b; /* 2 */ >> > >> > Either /*1*/ or /*2*/ should also result in a usable pointer that >> > passes the 'if' test above. That is to say, to the best of my >> > understanding that is how the language in the Standard should be >> > understood. >> >> Generally, I agree, with a warning: /*2*/ is meant to express >> reinterpretation (wich is basically what /*1*/ does as well), >> but is technically UB (you're accessing the value of `b' with >> an incompatible type lvalue), and might cause real trouble in >> real world (esp. when compiler optimization is turned on). > > Right, both on the technical UB and on the real potential > for problems. Thank you for pointing this out. I think /*1*/ was ok (all pointers to structs have the same representation), what might cause problems dereferencing it, but it won't in this case, since A is the first member of B. > Rather than /*2*/ we might consider /*2'*/: > > a = * (struct A *volatile *) &b; /* 2' */ > > Of course, this access still technically results in UB, but > it's unlikely that the access here will result in any real > world difficulties. Still wrong, look what a compiler might "think": TYPEA a; TYPEB b; //both types are incompatible b = something_b; //put something into b /*...*/ b = something_else_b; //put something else into b... but wait, let's cache //it in a register for now, and see what's next a = *(TYPEA volatile*)&b; //take the address of b, convert it to ptr to `volatile TYPEA', //dereference, take value and put into `a' //lvalue is type `volatile TYPEA'... hmm... nooooo, of course //it can't mean b here, let's read what that object contains, //and update b later... /* a contains something_b */ Perhaps `b' itself should be volatile in this case. -- Stan Tobias mailx `echo siXtY@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g` |
Re: Questions about pointers to objects and pointers to functions
"S.Tobias" <siXtY@FamOuS.BedBuG.pAlS.INVALID> writes:
> Tim Rentsch <txr@alumnus.caltech.edu> wrote: > > "S.Tobias" <siXtY@FamOuS.BedBuG.pAlS.INVALID> writes: > > > >> Tim Rentsch <txr@alumnus.caltech.edu> wrote: > >> > Marc Thrun <TekWarrior@gmx.de> writes: > >> > >> >> struct A { > >> >> int x; > >> >> }; > >> >> > >> >> and > >> >> > >> >> struct B { > >> >> struct A y; > >> >> int z; > >> >> }; > >> [snip] > >> > > >> > a = (struct A*) b; > >> > if( a == &b->y ) /* this 'if' will always be taken */ > >> > > >> > You might be asking about converting the object representation > >> > directly, eg, with one of > >> > > >> > memcpy( &a, &b, sizeof a ); /* 1 */ > >> > > >> > a = * (struct A**) &b; /* 2 */ > >> > > >> > Either /*1*/ or /*2*/ should also result in a usable pointer that > >> > passes the 'if' test above. That is to say, to the best of my > >> > understanding that is how the language in the Standard should be > >> > understood. > >> > >> Generally, I agree, with a warning: /*2*/ is meant to express > >> reinterpretation (wich is basically what /*1*/ does as well), > >> but is technically UB (you're accessing the value of `b' with > >> an incompatible type lvalue), and might cause real trouble in > >> real world (esp. when compiler optimization is turned on). > > > > Right, both on the technical UB and on the real potential > > for problems. Thank you for pointing this out. [snip] > > Rather than /*2*/ we might consider /*2'*/: > > > > a = * (struct A *volatile *) &b; /* 2' */ > > > > Of course, this access still technically results in UB, but > > it's unlikely that the access here will result in any real > > world difficulties. > > Still wrong, look what a compiler might "think": > > TYPEA a; > TYPEB b; > //both types are incompatible > b = something_b; > //put something into b > /*...*/ > b = something_else_b; > //put something else into b... but wait, let's cache > //it in a register for now, and see what's next > a = *(TYPEA volatile*)&b; > //take the address of b, convert it to ptr to `volatile TYPEA', > //dereference, take value and put into `a' > //lvalue is type `volatile TYPEA'... hmm... nooooo, of course > //it can't mean b here, let's read what that object contains, > //and update b later... > /* a contains something_b */ It's an interesting argument, but the reasoning is not quite sound. During code generation, the compiler keeps track (in the data flow sense) of where the value of 'b' is held at any given moment. When the address is taken ('&b'), the compiler is going to use the address of the location where 'b' is currently held. If 'b' is currently held in a register, and the address value might escape the context that the compiler can analyze, the register value of 'b' will be written back to its regular memory location so that the address will point to the currently meaningful value. Of course, what's going to happen in a real compiler in this situation is that the compiler will know that the (casted) address refers to 'b', and the register holding 'b' will simply be stored into 'a'. |
Re: Questions about pointers to objects and pointers to functions
Tim Rentsch <txr@alumnus.caltech.edu> wrote:
> "S.Tobias" <siXtY@FamOuS.BedBuG.pAlS.INVALID> writes: >> TYPEA a; >> TYPEB b; >> //both types are incompatible >> b = something_b; >> //put something into b >> /*...*/ >> b = something_else_b; >> //put something else into b... but wait, let's cache >> //it in a register for now, and see what's next >> a = *(TYPEA volatile*)&b; >> //take the address of b, convert it to ptr to `volatile TYPEA', >> //dereference, take value and put into `a' >> //lvalue is type `volatile TYPEA'... hmm... nooooo, of course >> //it can't mean b here, let's read what that object contains, >> //and update b later... >> /* a contains something_b */ > > It's an interesting argument, but the reasoning is not quite sound. > > During code generation, the compiler keeps track (in the data flow > sense) of where the value of 'b' is held at any given moment. When > the address is taken ('&b'), the compiler is going to use the address > of the location where 'b' is currently held. But taking the address of `b' does not automatically mean that the object `b' is going to be accessed. The decision which object _may_ be accessed can be based only on the type of lvalue and effective type of the object, and I believe that this optimization above is allowed. That's how I imagine aliasing rule works. But I'd still appreciate others' comments on this. >If 'b' is currently held > in a register, and the address value might escape the context that the > compiler can analyze, the register value of 'b' will be written back > to its regular memory location so that the address will point to the > currently meaningful value. Of course, what's going to happen in a > real compiler in this situation is that the compiler will know that > the (casted) address refers to 'b', and the register holding 'b' will > simply be stored into 'a'. But my point is that the context does *not* escape, it's just that the compiler determines that `b' cannot be accessed because the lvalue type doesn't match its effective type. Since all information is in one expression, it's easy to infer that in this case object `b' is going to be accessed. However, a compiler need not be that wise. Have you tried this with DS9000? -- Stan Tobias mailx `echo siXtY@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g` |
| All times are GMT. The time now is 07:49 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.