 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
jeffz_2002@yahoo.com Guest
|
Posted: Sun Jun 26, 2005 2:08 pm Post subject: Casting function pointer to different signature - compiler c |
|
|
/*
Hello,
To implement a C++ simulation I was working on, I started looking at
Vladimir Batov's code from CUJ, Feb 2001 ("Callbacks Made Easy with the
Observer-Mediator Design Patterns"). Most of the code is
straightforward, but I can't follow the central mechanism behind his
design that lets it work. I've boiled the problem down to the code
below -- specifically the function doSomethingVoidPtr, where casting a
function pointer's signature to a different signature lets the code
bypass the compiler's type checking of function arguments. The console
output follows the code.
As shown in line A, the function pointer doSomething gets cast to a
different signature. In line B, this function pointer is then called
with an address to an A, which has previously been cast to a void *.
Somehow, though I'm not sure how, the program manages to take this
address-of-an-A-as-ptr-to-void and convert it to a const A& argument,
as required by doSomething. Question: How and why does it do this? I
assumed that C++'s compiler would balk at this, but it compiled.
Some extra notes:
- I had to cast the whole function's signature to an f_t, I couldn't
just call doSomething with a void *.
- when I call this function pointer with a void * which contains an
address to a B (line C), the program gives garbage. It seems the code
is casting the void* to A's bit pattern (terminology?), and so trying
to get x_ from the non-A object gives crap (or will
crash program).
Thanks,
Jeff
P.S.: For the curious, the point in question in Batov's code is in the
method Parcel::call, where the function pointer member_callback_ is
given an event and a pointer-to-void sender. member_callback_ is then
cast to a different signature [typedef void (Callee::*MemberCallback)
(const Event&, void*)], when the Parcel object is created ... see the
macro #FAMILY in signals.h. Unfortunately, the article doesn't really
go into the casting of the of function pointer to different types,
which is unfortunate, since it's the trick that allows his pattern to
work.
*/
#include <iostream>
using namespace std;
struct A {
A(int x) : x_(x) {};
int x_;
};
struct B {};
void doSomething(const A& a) {
cout << "doSomething: " << a.x_ << endl;
}
void doSomethingVoidPtr(void* a) {
typedef void (*f_t)(void *);
// line A - casting doSomething to different signature.
f_t myFun = (f_t)doSomething;
// line B - calling the function, passing in a void* arg.
(*myFun)(a);
}
int main() {
A a(42);
cout << "Calling with an A: ";
doSomething(a);
void* p = &a;
// doSomething(p); // doesn't compile.
cout << "Calling with a void* pointing at an A: ";
doSomethingVoidPtr(p);
B b;
void* vb = &b;
cout << "Calling with a void* pointing at a B: ";
doSomethingVoidPtr(vb); // line C
return 0;
}
/* Output:
Calling with an A: doSomething: 42
Calling with a void* pointing at an A: doSomething: 42
Calling with a void* pointing at a B: doSomething: 586179681
*/
/* FYI:
$ g++ --version
g++ (GCC) 3.3.1 (cygming special)
Thanks! Jeff
*/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
jeffz_2002@yahoo.com Guest
|
Posted: Mon Jun 27, 2005 10:43 am Post subject: Re: Casting function pointer to different signature - compil |
|
|
// Hi folks, I just realized I could simplify the code for my question:
#include <iostream>
using namespace std;
struct A {
A(int x) : x_(x) {};
int x_;
};
struct B {};
void doSomething(const A& a) { cout << "doSomething: " << a.x_ << endl;
}
int main() {
A a(42);
B b;
typedef void (*void_func_void_ptr_arg)(void *);
void_func_void_ptr_arg f = (void_func_void_ptr_arg)doSomething; //
line A
void* vpa = &a;
(*f)(vpa); // line B ... prints "doSomething: 42"
void* vpb = &b;
(*f)(vpb); // line C ... prints "doSomething: 1089" (garbage)
return 0;
}
// Thanks, Jeff
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jack Klein Guest
|
Posted: Tue Jun 28, 2005 9:57 am Post subject: Re: Casting function pointer to different signature - compil |
|
|
On 27 Jun 2005 06:43:16 -0400, [email]jeffz_2002 (AT) yahoo (DOT) com[/email] wrote in
comp.lang.c++.moderated:
| Quote: | // Hi folks, I just realized I could simplify the code for my question:
#include
using namespace std;
struct A {
A(int x) : x_(x) {};
int x_;
};
struct B {};
void doSomething(const A& a) { cout << "doSomething: " << a.x_ << endl;
}
int main() {
A a(42);
B b;
typedef void (*void_func_void_ptr_arg)(void *);
void_func_void_ptr_arg f = (void_func_void_ptr_arg)doSomething; //
line A
void* vpa = &a;
(*f)(vpa); // line B ... prints "doSomething: 42"
void* vpb = &b;
(*f)(vpb); // line C ... prints "doSomething: 1089" (garbage)
return 0;
}
// Thanks, Jeff
|
The compiler does not cast anything at all. What you doing is
inducing undefined behavior. A pointer is not a reference and a
reference is not a pointer. You are making a call to a function and
passing an argument of a type different than that accepted by the
function. Anything that does or does not happen is not specified by
the C++ language and might just happen to be an artifact of the way
your compiler passes pointers and references.
The code just happens to work, or not work, as you observe, on your
particular implementation. From the C++ language point of view, it is
just plain undefined.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|