Hi.

Is is possible to create a lookup table of function pointers to functions with variable numbers/types of arguments?

If not, can anyone recommend a solution for my problem? I have a list of commands corresponding to functions with variable types/numbers of arguments. Some don't take any arguments. I was planning to use a LUT of function pointers; is there any alternative apart from a long list of if/else statements?
Please note I am restricted to using ansi C library functions (embedded project).
Any help greatly appreciated.

Recommended Answers

All 8 Replies

Just overload the function?

void function(char a) {
    std::cout << "with char";
}

void function(char a, char b) {
    std::cout << "with 2 chars";
}

void function(std::string a) {
    std::cout << "with string";
}

void function() {
    std::cout << "with no arguments";
}

void function(int a, int b, int c, int d) {
    std::cout << "with 4 integers";
}


int main(){
    function();
    function('a');
    function("something")
}

Or am I missing the point here?

The problem lies in the declaration of the lookup table. All the functions are already defined in an external DLL, and I can't touch them. Take a look at what I've got and you might have a better idea:

// A structure to hold all the commands and function pointers
typedef struct
{
    int (_stdcall *myfunction)(char *, char *);	// defines the function pointer
    char functionName[256]; // used to refer to the function pointer	
} LOOKUP_TABLE;

// This lookup table holds all TSL1 commands and their related functions
static const LOOKUP_TABLE lookUpTable[] = 
{ 
    {DIAG_ReadMem8, "ReadMemory8"},
    {DIAG_ReadMem16, "ReadMemory16"},
    {DIAG_ReadMem32, "ReadMemory32"},
    {DIAG_ReadMem64, "ReadMemory64"},
    {DIAG_WriteMem8, "WriteMemory8"},
    {DIAG_WriteMem16, "WriteMemory16"},
    {DIAG_WriteMem32, "WriteMemory32"},
    {DIAG_WriteMem64, "WriteMemory64"},
    {NULL, NULL} 
};

// Implememtation:
int n = sizeof(lookUpTable)/sizeof(*lookUpTable);
for (int i = 0; i < n; i++)
{
    if(strcmp(lookUpTable[i].functionName, sCmdInt[0]) == 0)
    {
        iError = lookUpTable[i].myfunction(sCmdInt[1], returnData);
    }

}

The problem now is that the "WriteMemory" commands take different arguments from the "ReadMemory" commands. Also there are many more variations of functions to follow. So issues arise with the declaration of the Lookup Table. ie:

int (_stdcall *myfunction)(char *, char *);// defines the function pointer

I cannot pass the same arguments for these functions; the following doesn't work for the write memory commands:

iError = lookUpTable[i].myfunction(sCmdInt[1], returnData);

Any suggestions?

You can't really do that, but there might always be some hack. How about you create
the most general lookup tables and work with that? Maybe something like readMemoryFunctionTable, writeMemoryFunctionTable,...

> The problem lies in the declaration of the lookup table.
> All the functions are already defined in an external DLL, and I can't touch them.

So write wrappers of your own that call the functions in the DLL.

> The problem now is that the "WriteMemory" commands take different arguments from the "ReadMemory" commands.
> Also there are many more variations of functions to follow. So issues arise with the declaration of the Lookup Table

Have wrapper variadic functions functions which unpack the arguments using <stdarg.h> then forward the call to the external function. And be extremely careful in doing this - make sure that you have no type errors.

#include <stdio.h>
#include <assert.h>
#include <stdarg.h>

int foo( const char* arg ) // external dll function
{ return printf( "foo( '%s' )\n", arg ) ; }

int bar( int arg1, double arg2 ) // external dll function
{ return printf( "bar( %d, %f )\n", arg1, arg2 ) ; }

typedef enum function_id_ { FOO = 1, BAR = 2 } function_id ;

int foo_wrapper( function_id id, ... )
{
    typedef const char* arg_type ;
    arg_type a ;

    assert( id == FOO ) ;

    va_list arg_list ;
    va_start( arg_list, id ) ;
    a = va_arg( arg_list, arg_type ) ;
    va_end( arg_list ) ;

    return foo(a) ;
}

int bar_wrapper( function_id id, ... )
{
    typedef int arg1_type ;
    typedef double arg2_type ;
    arg1_type a ;
    arg2_type b ;

    assert( id == BAR ) ;

    va_list arg_list ;
    va_start( arg_list, id ) ;
    a = va_arg( arg_list, arg1_type ) ;
    b = va_arg( arg_list, arg2_type ) ;
    va_end( arg_list ) ;

    return bar( a, b ) ;
}

typedef int function_type( function_id, ... ) ;

typedef struct lookup_table_entry_
{
    function_type* const function_pointer ;
    const function_id function_id ;
} lookup_table_entry ;

static const lookup_table_entry lookup_table[] =
{
    { foo_wrapper, FOO },
    { bar_wrapper, BAR },
    { 0, -1 }
};

enum { NFUNCTIONS = sizeof(lookup_table) / sizeof(*lookup_table) } ;

int main()
{
    function_id id = BAR ;
    int result = 0 ;
    int i ;
    for( i = 0 ; i < NFUNCTIONS ; ++i )
    {
        if( lookup_table[i].function_id == id )
        {
            result = lookup_table[i].function_pointer( id, 23, 456.789 ) ;
            break ;
        }
    }
    return result ;
}

Isn't there a lot of overhead in this? I have ~200 external DLL functions, so I'd need to write a wrapper for each one of them. Then pass entries into each lookup table. For a novice like me, do you think a long if/else would be more easily implemented? (This code will be running on a microcontroller, so code base size is something I need to keep in mind).

> For a novice like me, do you think a long if/else would be more easily implemented?

More easily implemented right now, yes. But 200 if/else if statements would not be pretty to maintain, and code size would be larger than that for a look up table.

> Isn't there a lot of overhead in this?
> I have ~200 external DLL functions, so I'd need to write a wrapper for each one of them.

In terms of performance overhead, 100 string comparisons are not great for performance; you could give each function a unique integral id and use much faster integer comparisons instead.

In terms of programmer overhead:

You would not need to write a wrapper for each of them; if these 200 functions fall into, say, 5 different types of function parameters, you would need just five forwarding wrappers.

An alternative approach would be to have five different look up tables, one for each function type.

As a simplified example, let's say you have just two different types of functions in all:

typedef int function_type_foo( const char* cstr ) ;
typedef int function_type_bar( int, double ) ;

With many functions of the same type:

int foo_one( const char* arg )
{ return printf( "foo_one( '%s' )\n", arg ) ; }

int foo_two( const char* arg )
{ return printf( "foo_two( '%s' )\n", arg ) ; }
// ...

int bar_one( int arg1, double arg2 )
{ return printf( "bar_one( %d, %.2f )\n", arg1, arg2 ) ; }

int bar_two( int arg1, double arg2 )
{ return printf( "bar_two( %d, %.2f )\n", arg1, arg2 ) ; }
// ...

We can give ids to these functions, segregated on range of values:

enum function_id {
                   NOTHING = 0,

                   FOO_ID_START = 1000,
                   FOO1 = 1001, FOO2 = 1002,

                   BAR_ID_START = 2000,
                   BAR1 = 2001, BAR2 = 2002

                   // ...
                  } ;

And have two look up tables, one for each type:

struct foo_lookup_table_entry
{
    const function_id id ;
    function_type_foo* const foo_pointer ;
} ;

struct bar_lookup_table_entry
{
    const function_id id ;
    function_type_bar* const bar_pointer ;
} ;

static const foo_lookup_table_entry foo_lookup_table[] =
{
    { FOO1, foo_one },
    { FOO2, foo_two },
    // ...
    { NOTHING, 0 }
};

static const bar_lookup_table_entry bar_lookup_table[] =
{
    { BAR1, bar_one },
    { BAR2, bar_two },
    // ...
    { NOTHING, 0 }
};

The typical look up based on function id would be
a. vector into the right table based on the range into which the id falls.
b. look up in that table for a matching id and call the function.

int invoke( function_id id )
{
    if( id < BAR_ID_START )
    {
        for( int i = 0 ; foo_lookup_table[i].id != NOTHING ; ++i )
            if( foo_lookup_table[i].id == id )
                return foo_lookup_table[i].foo_pointer("string") ;
    }
    else
    {
        for( int i = 0 ; bar_lookup_table[i].id != NOTHING ; ++i )
            if( bar_lookup_table[i].id == id )
                return bar_lookup_table[i].bar_pointer( 1, 2.3 ) ;
    }
    return -1 ;
}

A trivial test driver for the above:

int main()
{
    invoke( FOO1 ) ;
    invoke( BAR1 ) ;
    invoke( FOO2 ) ;
    invoke( BAR2 ) ;
}

Although not every single function is different, there is a lot of variation. Would it be efficient to create separate lookup tables for, say, common functions (i.e., there is a group of ~40 with the same params etc, another group with ~20), and then use an if/else for the individual distinct functions?

> Would it be efficient to create separate lookup tables for, say, common functions
> (i.e., there is a group of ~40 with the same params etc, another group with ~20)
> and then use an if/else for the individual distinct functions?

Efficiency requirements are design constraints; efficiency per se is not a design goal. The idea would be to get to a design that is simple, maintainable and flexible within the constraints imposed by efficiency needs.

So, I'd suggest: go ahead with that for the individual distinct functions. Perhaps with a switch/case on the function id instead of a sequence of if/ else ifs. Profile the code, measure its performance, and leave it at that if the performance is acceptable.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.