473,763 Members | 2,714 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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
Nov 15 '05 #1
15 1990
Marc Thrun <Te********@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?
Nov 15 '05 #2
Marc Thrun <Te********@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.
Nov 15 '05 #3
Tim Rentsch wrote:
Marc Thrun <Te********@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
unfortunate ly 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 ;-).
Nov 15 '05 #4
Marc Thrun <Te********@gmx .de> writes:
Tim Rentsch wrote:
Marc Thrun <Te********@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.
Nov 15 '05 #5
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
Marc Thrun <Te********@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
reinterpretatio n (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 si***@FamOuS.Be dBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #6
"S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> writes:
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
Marc Thrun <Te********@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
reinterpretatio n (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.
Nov 15 '05 #7
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
"S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> writes:
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
> Marc Thrun <Te********@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
reinterpretatio n (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 si***@FamOuS.Be dBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #8
"S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> writes:
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
"S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> writes:
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
> Marc Thrun <Te********@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
reinterpretatio n (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'.
Nov 15 '05 #9
Tim Rentsch <tx*@alumnus.ca ltech.edu> wrote:
"S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> 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 si***@FamOuS.Be dBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

71
5936
by: cj | last post by:
Dear friends, I have one more questions for everyone in the newsgroup: I am preparing for an interview on UNIX/C++. Could you please identify some of the most important questions which might be asked, so that I could best prepare for it? Thank you, C++J
2
2013
by: Thomas Matthews | last post by:
Hi, I would like to create a table (or vector) of pointers to templated functions. 1. How do I declare a typedef of a pointer to a templated function? For example, I have some functions that print out a type's name to an istream:
14
1986
by: MSR | last post by:
I have a couple of questions. 1. Copy Constructor. class A { private: int a1; double d1; char *ptr;
9
1630
by: Gonçalo Rodrigues | last post by:
Hi all, I have a few questions on primitive types that I will divide in two main questions. I realize that some of these questions -- especially 2. below -- are not directly related to C++ as a language itself, so, if there is a better newsgroup to make them would you be so kind and please direct me to it? 1. Assume that in your platform (OS + compiler) all pointer types have the same size. Is there a platform independent way to get...
8
1611
by: V.Ch. | last post by:
In near future I can face a prospect of writing some stuff in C. Being a C++ programmer, I've got practically no experience in C. I'd be obliged if someone could answer the following questions (from specific to more general): 1. Having looked though some C sources I was horrified by the number of macros. E.g., what could be the purpose of using this: #define CFG_REF(c, f) ((c) -> f) #define SERVER_ADDRESS(c) CFG_REF (c, server_address)
7
1763
by: alternativa | last post by:
Hello, I have a few questions concerning classes. 1) Why some people use default constructos, i.e constructors with no parameters? To me it doesn't make any sense, is there something I should know? For example, I'd declare a class in a following way: class Sample { int number; string title;
22
1767
by: Guru Jois | last post by:
Hai all, I have some question. Please answer. 1. What is walking pointer? 2. What is difference between procedure and subroutine? 3. What is template of main in C? 4. What is padding of structure ( or structure padding )? 5. What is advantages of using pointers to functions?.
7
8246
by: irshadjat | last post by:
Question No.01 Which of the following is true about streams? A. It is a sequence of bytes B. It is an ordered sequence C. All bytes can go through the stream simultaneously D. Bytes that enters first into the stream will go out at last 0 A only 0 C only 0 A and B
7
1430
by: tradevol | last post by:
as this example, question: If my purpose is initialize data from xml files and store them in the vector, so they can be used in class B by other member functions, do you think functionP is a viable function(will a could go away after out of the function)? If not, is there a better solution than using functionPt?
0
9563
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10145
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9938
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9822
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7366
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6642
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5406
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3917
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2793
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.