Casting function pointers to and from void*

P

Peter Olcott

I want to make a generic interface between a scripting language and native code,
the native code and the interpreter will both be written in C++. The interpreter
will probably be implemented as a subset of C/C++, thus will have the same
syntax as C/C++.

Somehow the interpreted code must be able to store generic function pointers
because there is no way for the interpreter to know every possible function
signature in advance. I was thinking about casting them to void* for this
purpose.

The interpreted function will be provided with the generic function pointer, and
the function prototype as text. The interpreter will prepare the stack itself
based on this function prototype. What I want to end up with is a simple
interface for users of the interpreter that is identical to the interface for
the native code users.

In other words if the function prototype is:
int FunctionName(int N);
I want uses of my interpreter to be able to specify:
int Result = FunctionName(56);
when they are calling the native code functions.

What kind of C++ syntax will be needed for this?
 
N

Noah Roberts

Peter said:
I want to make a generic interface between a scripting language and native code,
the native code and the interpreter will both be written in C++. The interpreter
will probably be implemented as a subset of C/C++, thus will have the same
syntax as C/C++.

Somehow the interpreted code must be able to store generic function pointers
because there is no way for the interpreter to know every possible function
signature in advance. I was thinking about casting them to void* for this
purpose.

The interpreted function will be provided with the generic function pointer, and
the function prototype as text. The interpreter will prepare the stack itself
based on this function prototype. What I want to end up with is a simple
interface for users of the interpreter that is identical to the interface for
the native code users.

In other words if the function prototype is:
int FunctionName(int N);
I want uses of my interpreter to be able to specify:
int Result = FunctionName(56);
when they are calling the native code functions.

What kind of C++ syntax will be needed for this?

I don't understand your problem as stated but maybe boost::function
will aid you.
 
P

Philipp Reh

I want to make a generic interface between a scripting language and native code,
the native code and the interpreter will both be written in C++. The interpreter
will probably be implemented as a subset of C/C++, thus will have the same
syntax as C/C++.

Somehow the interpreted code must be able to store generic function pointers
because there is no way for the interpreter to know every possible function
signature in advance. I was thinking about casting them to void* for this
purpose.

The interpreted function will be provided with the generic function pointer, and
the function prototype as text. The interpreter will prepare the stack itself
based on this function prototype. What I want to end up with is a simple
interface for users of the interpreter that is identical to the interface for
the native code users.

In other words if the function prototype is:
int FunctionName(int N);
I want uses of my interpreter to be able to specify:
int Result = FunctionName(56);
when they are calling the native code functions.

What kind of C++ syntax will be needed for this?

You can't cast a pointer to a function to a pointer to an object.
reinterpret_cast can convert between two pointers to different functions
only.
 
P

Peter Olcott

Philipp Reh said:
You can't cast a pointer to a function to a pointer to an object.
reinterpret_cast can convert between two pointers to different functions
only.

Is there any standard C++ way to accomplish what I need to accomplish?
 
P

Peter Olcott

Philipp Reh said:
You can't cast a pointer to a function to a pointer to an object.
reinterpret_cast can convert between two pointers to different functions
only.

void Test() {
printf("Hello World!\n");
}

void (*pf)() = Test;

void* vp = (void*) pf;

This all compiles and executes correctly on my compiler.

// All I need now is something like:
goto *vp;
// sets the instruction pointer to the address contain in vp.

Is there anyway that anything like this can be done in standard C++ ???
 
P

Peter Olcott

Marcus Kwok said:
Even though it *seems* to work, it is not correct.

It indeed does work, I checked the generated assembly language. It only has to
work on a single platform/compiler. When getting the job done requires breaking
the rules, the rules must be broken.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Peter said:
When getting the job done requires breaking the rules, the rules must be
broken.

Please don't blame the job when it's you who decide to break the rules.
 
M

Marcus Kwok

Peter Olcott said:
It indeed does work, I checked the generated assembly language. It only has to
work on a single platform/compiler. When getting the job done requires breaking
the rules, the rules must be broken.

Sure, but then it is no longer Standard C++. Sorry, I don't have an
answer to your real question. Maybe someone on a group for your
platform or compiler will have a suggestion that is known to work for
your situation.
 
P

Peter Olcott

Julián Albo said:
Please don't blame the job when it's you who decide to break the rules.

I don't have to get my system working in theory, I have to get it working in
practice. If it does not work in theory yet does work in practice, then the
theory is discarded.
 
P

Peter Olcott

Marcus Kwok said:
Sure, but then it is no longer Standard C++. Sorry, I don't have an
answer to your real question. Maybe someone on a group for your
platform or compiler will have a suggestion that is known to work for
your situation.

I was able to infer that casting to a specific function pointer type would not
generally be possible. It would not generally be possible because the function
pointer requires the compile time support of preparing the stack.
 
G

Gavin Deane

Peter said:
I don't have to get my system working in theory, I have to get it working in
practice. If it does not work in theory yet does work in practice, then the
theory is discarded.

The problem you create for yourself when you take this approach is that
you have no way of knowing for how long your solution will continue to
work in practice. Examining the generated assembly language is a valid
way of checking that the behaviour in practice of your code is what you
want when the behaviour in theory is formally undefined. However,
unless your compiler documents the behaviour in practice as an
extension (which it may well do), you have no way of knowing how stable
the behaviour in practice is in the face of changes, such as compiler
options, debug vs release build, or a change in the code itself. Your
code is potentially very brittle. Every time you change something and
recompile, you have to reexamine the generated assembly language to see
if you still have the behaviour in practice that you need.

Only you know how likely such changes and the associated need to
recompile are, so only you are in a position to assess the relative
costs of losing robustness in the code vs. redesigning to avoid the
problem in the first place. But it is an assessment you must make.

Gavin Deane
 
G

Greg

Marcus said:
Sure, but then it is no longer Standard C++. Sorry, I don't have an
answer to your real question. Maybe someone on a group for your
platform or compiler will have a suggestion that is known to work for
your situation.

Function-to-object pointer conversions have been added to standard C++
as a "conditionally supported" conversion using reinterpret_cast<>:

"Converting a pointer to a function into a pointer to an object type or
vice versa is conditionally-supported. The meaning of such a conversion
is implementation defined, except that if an implementation supports
conversions in both directions, converting an rvalue of one type to the
other type and back, possibly with different cv-qualification, shall
yield the original pointer value." [expr.reinterpret.cast/8]

Conditionally-supported behavior is one that an implementation is not
required to support. But an implementation does support the feature
must then implement the feature as specified.

Greg
 
P

Pete Becker

Gavin said:
The problem you create for yourself when you take this approach is that
you have no way of knowing for how long your solution will continue to
work in practice. Examining the generated assembly language is a valid
way of checking that the behaviour in practice of your code is what you
want when the behaviour in theory is formally undefined. However,
unless your compiler documents the behaviour in practice as an
extension (which it may well do), you have no way of knowing how stable
the behaviour in practice is in the face of changes, such as compiler
options, debug vs release build, or a change in the code itself. Your
code is potentially very brittle. Every time you change something and
recompile, you have to reexamine the generated assembly language to see
if you still have the behaviour in practice that you need.

Only you know how likely such changes and the associated need to
recompile are, so only you are in a position to assess the relative
costs of losing robustness in the code vs. redesigning to avoid the
problem in the first place. But it is an assessment you must make.

Despite all these dire threats, Unix programmers have been storing
function pointers in void*'s for years. I'd even be so bold as to
suggest that any compiler that didn't suppport this idiom on a Unix
system where code and data pointers are the same size would be a
failure. At the end of the day, it's more important to have code that
works than to be hypothetically pure.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Pete said:
Despite all these dire threats, Unix programmers have been storing
function pointers in void*'s for years.

An many unix or non unix programs have failed to work when compiled on
different machines or compilers for decades. Maybe there are some
correlation...
 
M

Marcus Kwok

Greg said:
Function-to-object pointer conversions have been added to standard C++
as a "conditionally supported" conversion using reinterpret_cast<>:

"Converting a pointer to a function into a pointer to an object type or
vice versa is conditionally-supported. The meaning of such a conversion
is implementation defined, except that if an implementation supports
conversions in both directions, converting an rvalue of one type to the
other type and back, possibly with different cv-qualification, shall
yield the original pointer value." [expr.reinterpret.cast/8]

Interesting, thanks.
Conditionally-supported behavior is one that an implementation is not
required to support. But an implementation does support the feature
must then implement the feature as specified.

Is there a consolidated list of other "conditionally-supported"
features?
 
G

Gavin Deane

Pete said:
Despite all these dire threats, Unix programmers have been storing
function pointers in void*'s for years. I'd even be so bold as to
suggest that any compiler that didn't suppport this idiom on a Unix
system where code and data pointers are the same size would be a
failure. At the end of the day, it's more important to have code that
works than to be hypothetically pure.

Clearly, code that doesn't work is no use. If such code is formally
correct and, according to the standard should work, you have a QoI
issue, unless your compiler documents its intended deviation from the
standard.

It is important that code works. Often (very often in my personal
experience), it is also important that the code continues to work in
the face of changes. Unless you have an inside line to the people who
make your compiler, the language standard and your compiler's
documentation of any omissions, extensions or variations from the
language standard are your only means of knowing how the compiler
manufacturer intends any C++ code to behave after their compiler has
compiled it. If you step outside that, you're on your own, flying
blind. As an engineer, stepping outside the manufacturer's
specification should be a big decision.

Gavin Deane
 
P

Pete Becker

Gavin said:
Clearly, code that doesn't work is no use. If such code is formally
correct and, according to the standard should work, you have a QoI
issue, unless your compiler documents its intended deviation from the
standard.

It is important that code works. Often (very often in my personal
experience), it is also important that the code continues to work in
the face of changes. Unless you have an inside line to the people who
make your compiler, the language standard and your compiler's
documentation of any omissions, extensions or variations from the
language standard are your only means of knowing how the compiler
manufacturer intends any C++ code to behave after their compiler has
compiled it. If you step outside that, you're on your own, flying
blind. As an engineer, stepping outside the manufacturer's
specification should be a big decision.

You're welcome to spend as much time as you like seeking purity. I'll
trust Unix compilers to continue support standard idioms such as storing
function addresses in void*'s, and I'll have robust, working code long
before you do.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Pete said:
You're welcome to spend as much time as you like seeking purity. I'll
trust Unix compilers to continue support standard idioms such as storing
function addresses in void*'s, and I'll have robust, working code long
before you do.

Did you have? Looks like you are asking for advice because you haven't.
 

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

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top