Calling a function of unknown type

C

Calum

I need to call a function in a shared library, but the type of the
function is not known until run-time.

enum Type { Void=0, Char, Uchar, Short, Ushort, Int, Uint, Float,
Double, String };

void call_unknown_function(
void *function,
enum Type retType, void *retAddress,
...);

The variable arguments are pairs of (Type,pointer), terminated by 0. So
to call double sqrt(double), it would be

double result, n=2.0;
call_unknown_function(sqrt, Double, &result, Double, &n, 0);

So how could I implement such a function? I would prefer not to resort
to assembly language.

Cheers,
Calum
 
E

Eric Sosman

Calum said:
I need to call a function in a shared library, but the type of the
function is not known until run-time.

enum Type { Void=0, Char, Uchar, Short, Ushort, Int, Uint, Float,
Double, String };

void call_unknown_function(
void *function,
enum Type retType, void *retAddress,
...);

The variable arguments are pairs of (Type,pointer), terminated by 0. So
to call double sqrt(double), it would be

double result, n=2.0;
call_unknown_function(sqrt, Double, &result, Double, &n, 0);

So how could I implement such a function? I would prefer not to resort
to assembly language.

C's "code model" is static: the language provides no means
to create and execute code at run-time. In particular, the
language provides no means to generate and execute an arbitrary
function call at run-time.

If the set of "signatures" -- combinations of result types
and argument lists -- is small, you can use the Type values to
select one of several pre-written calls and execute that one:

switch (result_Type) {
case Int:
switch (argument_signature) {
case Empty:
int_result = ((int)(*)(void)) fptr(void);
break;
case One_Int:
int_result = ((int)(*)(int)) fptr(int_arg[0]);
break;
case One_Double:
int_result = ((int)(*)(double)) fptr(dbl_arg[0]);
break;
case Int_and_Double:
int_result = ((int)(*)(int,double))
fptr(int_arg[0], dbl_arg[1]);
break;

.... and so on. (Obviously, there's code in addition to this snip.)
Note the casts of the function pointer argument: at the point of
the call, the pointer type must agree with the actual function
being called. And since there's no "generic" function pointer
akin to `void*' for object pointers, call_unknown_function() must
be defined as taking some specific function pointer type, and the
call to call_unknown_function() must cast the actual function pointer
to that type, e.g.:

void call_unknown_function(void (*fptr)(void), ...);

call_unknown_function( (void (*)(void))sqrt,
Double, &result, Double, &n, 0);

All in all, it's not an entirely satisfactory solution: it's
inflexible, error-prone, and prolix. Although I've used the
technique, I'd suggest you seek alternative approaches to solve
whatever your over-arching problem may be; almost anything is
better than this kind of mess.
 
T

Thomas Matthews

Calum said:
I need to call a function in a shared library, but the type of the
function is not known until run-time.

enum Type { Void=0, Char, Uchar, Short, Ushort, Int, Uint, Float,
Double, String };

void call_unknown_function(
void *function,
enum Type retType, void *retAddress,
...);

The variable arguments are pairs of (Type,pointer), terminated by 0. So
to call double sqrt(double), it would be

double result, n=2.0;
call_unknown_function(sqrt, Double, &result, Double, &n, 0);

So how could I implement such a function? I would prefer not to resort
to assembly language.

Cheers,
Calum

Pass a pointer to data and an identifier indicating the data's type.
Use a switch statement or lookup table to defer execution to an
appropriate function will dereference the pointer correctly.

#include <stdio.h>
#include <stdlib.h>

enum Variable_type{VAR_VOID, VAR_CHAR, VAR_UCHAR, /* ... */};

void add_char(const void * ptr_to_first_argument,
const void * ptr_to_second_argument,
void * ptr_to_result)
{
char first_argument;
char second_argument;
char * p_result;

first_argument = *((char *) ptr_to_first_argument);
second_argument = *((char *) ptr_to_second_argument);
p_result = (char *) ptr_to_result;
*p_result = first_argument + second_argument;
return;
}


void add(enum Variable_Type variable_ID,
const void * ptr_to_first_argument,
const void * ptr_to_second_argument,
void * ptr_to_to_result)
{
switch (variable_ID)
{
case VAR_CHAR:
add_char(ptr_to_first_argument, ptr_to_second_argument,
ptr_to_ptr_to_result);
break;
/* etc. */
}
return;
}

int main(void)
{
char a = 5;
char b = 11;
char result;

add(VAR_CHAR, &a, &b, &result);
printf("%d + %d == %d\n", a, b, result);
return EXIT_SUCCESS;
}

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
C

Calum

Calum said:
I need to call a function in a shared library, but the type of the
function is not known until run-time.

enum Type { Void=0, Char, Uchar, Short, Ushort, Int, Uint, Float,
Double, String };

void call_unknown_function(
void *function,
enum Type retType, void *retAddress,
...);

The variable arguments are pairs of (Type,pointer), terminated by 0. So
to call double sqrt(double), it would be

double result, n=2.0;
call_unknown_function(sqrt, Double, &result, Double, &n, 0);

So how could I implement such a function? I would prefer not to resort
to assembly language.

Cheers,
Calum

Oops, it's in the faq. I did not expect this :)

So I now have some info to get started with. Though, I am using
Microsoft C++, so has anyone had any specific success doing this on that
compiler, I would like to hear about it.

Cheers,
Calum
 
C

Calum

Calum said:
I need to call a function in a shared library, but the type of the
function is not known until run-time.

enum Type { Void=0, Char, Uchar, Short, Ushort, Int, Uint, Float,
Double, String };

void call_unknown_function(
void *function,
enum Type retType, void *retAddress,
...);

The variable arguments are pairs of (Type,pointer), terminated by 0. So
to call double sqrt(double), it would be

double result, n=2.0;
call_unknown_function(sqrt, Double, &result, Double, &n, 0);

I have a solution to this problem. In C, the alternatives are
- Use a large switch statement (portable, tedious, always incomplete)
- Hack the stack (tedious, not portable)

However I have devised a portable solution in C++ involving templates.
Since this is a C group, I won't post it in its entirety, the code can
be found at http://visula.org/calum/dynargs.zip

The resulting library can however be called from C. This is (bizarrely)
an example of a C library being implemented in C++, usually it is the
other way around.

e.g.
double x, y=49.0;
dyn_apply(sqrt, double_t, &x, double_t, &y, 0);
// x = 7.0

Calum
 

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,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top