Honneamise
Honneamise

Reputation: 60

C implementation for generic function with varargs

I need to write the implementation of a function that accept as parameters:

The function prototype should be something like this :

void caller_imp( generic_function_pointer, varargs_list )

Suppose you have the following code example:

#define caller(function, ...) caller_imp(function, __VA_ARGS__)

int test (int a)
{
    return a;
}

int test2(int a, int b)
{
    return a+b;
}

void caller_imp(???,???)
{
    ???
}

int main(int argc, char **argv)
{
    caller(test,33);
    
    caller(test2,44,55);
    
    return 0;
}

Of consequence im in need to write the proper implementation of the "caller_imp" function.

UPDATED DETAILS :

int test (int a)
int test2(int a, int b)

are only an example, the function pointer and the parameters coul be varying, for example :

int test3(int a,char *str)

should be considered valid

unfortunatly I dont know which function pointer will be called or the number of the parameters or their type.

In C++ I think I could do :

template<typename Function, typename... Params>
auto call_imp(Function function, Params... params)
->typename std::enable_if<std::is_same<void,decltype(function(params...))>::value,decltype(function(params...))>::type
{
    function(std::forward<Params>(params)...);
}

Thanks in advance.

Upvotes: 0

Views: 168

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 222669

This is not supported in the C standard because there is no information available about what parameters a function expects. That is, given a function pointer alone, we cannot know whether the function expects one int argument, two int arguments, one int and one char * argument, or something else. Therefore, even if we had a way to dynamically construct an argument list, we would not know which argument list to construct.

If you do know which function requires which arguments, you can write specific code for each case:

#include <stdarg.h>

void caller_imp(void (*f)(void),...)
{
    va_list ap;
    va_start(ap, f);
    if (f == (void (*)(void)) test)
    {
        int a = va_arg(ap, int);
        ((int (*)(int)) f)(a);
    }
    else if (f == (void (*)(void)) test2)
    {
        int a = va_arg(ap, int);
        int b = va_arg(ap, int);
        ((int (*)(int, int)) f)(a, b);
    }
    va_end(ap);
}

Then the caller macro should convert the function pointer:

#define caller(function, ...) caller_imp((void (*)(void))(function), __VA_ARGS__)

If you do not know which function requires which arguments, it would be necessary to provide this information in some way, such as creating an enumeration of function types and requiring the caller to provide it.

Upvotes: 2

Lundin
Lundin

Reputation: 213810

You can do this to allow either 1 or 2 arguments of type int:

#define COUNT_ARGS(...) ( sizeof (int[]){__VA_ARGS__} / sizeof(int) )
#define caller(function, ...) (COUNT_ARGS(__VA_ARGS__) == 1 ? function : function##2) (__VA_ARGS__)

Usage:

caller(test, 1);
caller(test, 1, 2);

Please note that error handling is pretty non-existent here though...

Upvotes: 1

Related Questions