C implementation for generic function with varargs - c

I need to write the implementation of a function that accept as parameters:
a function pointer
a list of 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.

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.

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...

Related

How to define functions inside an array in C? [duplicate]

I have a struct that contains a declaration like this one:
void (*functions[256])(void) //Array of 256 functions without arguments and return value
And in another function I want to define it, but there are 256 functions!
I could do something like this:
struct.functions[0] = function0;
struct.functions[1] = function1;
struct.functions[2] = function2;
And so on, but this is too tiring, my question is there some way to do something like this?
struct.functions = { function0, function1, function2, function3, ..., };
EDIT: Syntax error corrected as said by Chris Lutz.
I have a struct that contains a declaration like this one:
No you don't. That's a syntax error. You're looking for:
void (*functions[256])();
Which is an array of function pointers. Note, however, that void func() isn't a "function that takes no arguments and returns nothing." It is a function that takes unspecified numbers or types of arguments and returns nothing. If you want "no arguments" you need this:
void (*functions[256])(void);
In C++, void func() does mean "takes no arguments," which causes some confusion (especially since the functionality C specifies for void func() is of dubious value.)
Either way, you should typedef your function pointer. It'll make the code infinitely easier to understand, and you'll only have one chance (at the typedef) to get the syntax wrong:
typedef void (*func_type)(void);
// ...
func_type functions[256];
Anyway, you can't assign to an array, but you can initialize an array and copy the data:
static func_type functions[256] = { /* initializer */ };
memcpy(mystruct.functions, functions, sizeof(functions));
I had the same problem, this is my small program to test the solution. It looks pretty straightforward so I thought I'd share it for future visitors.
#include <stdio.h>
int add(int a, int b) {
return a+b;
}
int minus(int a, int b) {
return a-b;
}
int multiply(int a, int b) {
return a*b;
}
typedef int (*f)(int, int); //declare typdef
f func[3] = {&add, &minus, &multiply}; //make array func of type f,
//the pointer to a function
int main() {
int i;
for (i = 0; i < 3; ++i) printf("%d\n", func[i](5, 4));
return 0;
}
You can do it dynamically... Here is a small example of a dynamic function array allocated with malloc...
#include <stdio.h>
#include <stdlib.h>
typedef void (*FOO_FUNC)(int x);
void a(int x)
{
printf("Function a: %d\n", x);
}
void b(int x)
{
printf("Function b: %d\n", x);
}
int main(int argc, char **argv)
{
FOO_FUNC *pFoo = (FOO_FUNC *)malloc(sizeof(FOO_FUNC) * 2);
pFoo[0] = &a;
pFoo[1] = &b;
pFoo[0](10);
pFoo[1](20);
return 0;
}
From the top of my head and untested.
// create array of pointers to functions
void (*functions[256])(void) = {&function0, &function1, &function2, ..., };
// copy pointers to struct
int i;
for (i = 0; i < 256; i++) struct.functions[i] = functions[i];
EDIT: Corrected syntax error as said by Chris Lutz.
You could do that while declaring your struct instance:
function_structur fs = { struct_field1,
struct_field2,
{function0, function1, ..., function255},
struct_field3,
... };
You cannot use this shortcut for initialize arrays after the array has been declared: if you need to do that, you'll have to do it dynamically (using a loop, a memcpy or something else).
If you want to post-initialize an array using form like {func1, func2, ...}, this can be accomplished in the following way (using GCC):
UPD (thanks to Chris Lutz for remarks)
Define a macro like this:
#define FUNCTION_VECTOR_COPY(destVec, sourceVec) memcpy(destVec, sourceVec, sizeof(sourceVec))
And pass source vector using Compound Literals, as follow:
#include <string.h>
...
void (*functions[256])();
...
FUNCTION_VECTOR_COPY (functions, ((void(*[])()) {func1, func2, func3}));

How to write to variables passed to the Variadic function in C

I'm totally new to C and I'm wondering is it possible to create a variadic function and pass pointers of variables into it and write data into the variables?
One obvious example of what I'm looking for is the scanf function which takes the input from the stdin and writes it into the variables.
Here is a sample of want I want to do:
void fun(int num, ...){
// insert 2 in a and "abc" in b
}
int main(void){
int a;
char *b;
fun(2, &a, &b);
}
update I can alter my constructor to get variables pattern instead of the number of them, so here is the code after modification:
void fun(char *fmt, ...){
// insert 2 in a and "abc" in b
}
int main(void){
int a;
char *b;
fun("dc", &a, &b);
}
Start with the example code shown in the stdarg man page (man 3 stdarg). Slightly modified for readability, and adding a trivial main():
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
void foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt) {
switch (*(fmt++)) {
case 's':
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd':
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c':
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
}
va_end(ap);
}
int main(void)
{
char *s1 = "First";
char *s2 = "Second";
int d = 42;
char c = '?';
foo("sdcs", s1, d, c, s2);
return EXIT_SUCCESS;
}
If you compile and run the above, it will output
string First
int 42
char ?
string Second
As liliscent and Jonathan Leffler commented to the question, the key point is that we need a way to describe the type of each variadic argument. (In C, type information is essentially discarded at compile time, so if we want to support multiple types for one argument, we must also pass its type explicitly: the type (of a variadic function argument) simply does not exist at run time anymore.)
Above, the first parameter, fmt, is a string where each character describes one variadic argument (by describing its type). Thus, there are expected to be the same number of variadic arguments as there are s, d, or c characters in the fmt string.
The printf family of functions and the scanf family of functions both use % to indicate a variadic argument, followed by the formatting details and type specification of that argument. Because of the quite complex formatting they support, the code implementing those is much more complicated than the above example, but the logic is very much the same.
In an update to the question, OP asked if the function can change the value of the variadic arguments -- or rather, the values pointed to by the variadic arguments, similar to how scanf() family of functions work.
Because parameters are passed by value, and va_arg() yields the value of the parameter, and not a reference to the parameter, any modifications we make to the value itself locally (to s, d, or c in the foo() function example above) will not be visible to the caller. However, if we pass pointers to the values -- just like scanf() functions do --, we can modify the values the pointers point to.
Consider a slightly modified version of the above foo() function, zero():
void zero(char *fmt, ...)
{
va_list ap;
int *d;
char *c, **s;
va_start(ap, fmt);
while (*fmt) {
switch (*(fmt++)) {
case 's':
s = va_arg(ap, char **);
if (s)
*s = NULL;
break;
case 'd':
d = va_arg(ap, int *);
if (d)
*d = 0;
break;
case 'c':
/* pointers are fully promoted */
c = va_arg(ap, char *);
if (c)
*c = 0;
break;
}
}
va_end(ap);
}
Note the differences to foo(), especially in the va_arg() expressions. (I would also suggest renaming d, c, and s to dptr, cptr, and sptr, respectively, to help remind us humans reading the code that they are no longer the values themselves, but pointers to the values we wish to modify. I omitted this change to keep the function as similar to foo() as possible, to keep it easy to compare the two functions.)
With this, we can do for example
int d = 5;
char *p = "z";
zero("ds", &d, &p);
and d will be cleared to zero, and p to be NULL.
We are not limited to a single va_arg() within each case, either. We can, for example, modify the above to take two parameters per formatting letter, with the first being a pointer to the parameter, and the second the value:
void let(char *fmt, ...)
{
va_list ap;
int *dptr, d;
char *cptr, c, **sptr, *s;
va_start(ap, fmt);
while (*fmt) {
switch (*(fmt++)) {
case 's':
sptr = va_arg(ap, char **);
s = va_arg(ap, char *);
if (sptr)
*sptr = s;
break;
case 'd':
dptr = va_arg(ap, int *);
d = va_arg(ap, int);
if (dptr)
*dptr = d;
break;
case 'c':
cptr = va_arg(ap, char *);
/* a 'char' type variadic argument
is promoted to 'int' in C: */
c = (char) va_arg(ap, int);
if (cptr)
*cptr = c;
break;
}
}
va_end(ap);
}
This last function you can use via e.g.
int a;
char *b;
let("ds", &a, 2, &b, "abc");
which has the same effect as a = 2; b = "abc";. Note that we do not modify the data b points to; we just set b to point to a literal string abc.
In C11 and later, there is a _Generic keyword (see e.g. this answer here), that can be used in conjunction with preprocessor macros, to choose between expressions depending on the type(s) of the argument(s).
Because it does not exist in earlier versions of the standards, we now have to use for example sin(), sinf(), and sinl() to return the sine of their argument, depending on whether the argument (and desired result) is a double, float, or a long double. In C11, we can define
#define Sin(x) _Generic((x), \
long double: sinl, \
float: sinf, \
default: sin)(x)
so that we can just call Sin(x), with the compiler choosing the proper function variant: Sin(1.0f) is equivalent to sinf(1.0f), and Sin(1.0) is equivalent to sin(1.0), for example.
(Above, the _Generic() expression evaluates to one of sinl, sinf, or sin; the final (x) makes the macro evaluate to a function call with the macro parameter x as the function parameter.)
This is not a contradiction to the earlier section of this answer. Even when using the _Generic keyword, the types are checked at compile time. It is basically just syntactic sugar on top of macro parameter type comparison checking, that helps writing type-specific code; in other words, a kind of a switch..case statement that acts on preprocessor macro parameter types, calling exactly one function in each case.
Furthermore, _Generic does not really work with variadic functions. In particular, you cannot do the selection based on any variadic arguments to those functions.
However, the macros used can easily look like variadic functions. If you want to explore such generics a bit further, see e.g. this "answer" I wrote some time ago.

C - Passing function with unknown params to another function, and calling it

I'm trying to achieve something like this:
void sum(int a, int b){ printf("result: %d", a+b); }
void callFunc(void (*funct)(...), ...)
{
va_list ars;
va_start(ars, funct);
funct(ars);
va_end(ars);
}
int main()
{
callFunc(sum, 2,3);
return 0;
}
But this doesn't work, because of needing of two va_lists, for funct params and arguments passed. However, even if i try to pass the sum function, it says:error: invalid conversion from 'void (*)(int, int)' to 'void (*)(...)'
So how to make this work good old C-style?
You can't do it like that. It's just simply not possible.
The best you can do (while keeping it generic) is change funct to take a va_list, much like vprintf. But that probably won't work very well for your purposes.
Alternatively, you can do a macro:
#include <stdio.h>
#define CALL_FUNC(func, ...) func(__VA_ARGS__)
void sum(int a, int b){ printf("result: %d", a+b); }
int main()
{
CALL_FUNC(sum, 2, 3);
return 0;
}

using #ifdef for different number of function argument depending on platforms

I have a requirement that states a function should take in one new argument at the beginning of the argument list for a new platform I am working on.
so the following would be a prototype for this new platform
void foo (int newarg, const char * a, int b, int c);
where as in the previous case it was just
void foo (const char * a, int b, int c);
My concern is readability and code space . So I am thinking of using ifdefs but i am not sure if it is a good idea to use if def with in a argument list.
1)
void foo (
#ifdef __NEWPLATFORM__
int newarg,
#else
const char * a, int b, int c
#endif
);
or
#if __NEWPALTFORM__
void foo (int newarg, const char * a, int b, int c);
#else
void foo (const char * a, int b, int c);
#endif
Btw I cannot put the new argument to the end of the list which would make it a lot easier.
Which one of the two (or maybe a better solution) is better?
Thanks
Given that you are changing all the calls to foo,
just change foo to the function with more parameters, then #ifdef internal to the function for different functionality.
void foo (int newarg, const char * a, int b, int c){
#ifdef __NEWPALTFORM__
#else
#endif
}
Also worth considering whether the parameters to the function should really be a struct, in which case new parameters in the future won't be much of an issue. Not enough context in your question to say whether this is a good idea or not
but it would be something like :=
typedef struct {
int newarg;
const char* a;
int b;
int c;
} fooType;
void foo(fooType f) // either by value or by pointer depending on context
{
// #ifdefs...
}
A third option would be to conditionally define a symbol for the extra argument. You might use the #ifdef section to include other useful platform related stuff, for example:
#ifdef MY_NEW_PLATFORM
#define EXTRA_ARGS int newarg,
#define GET_EXTRA newarg
#define SET_EXTRA(val) newarg = (val)
#else
#define EXTRA_ARGS
#define GET_EXTRA 0
#define SET_EXTRA(val)
#endif
...
void foo (EXTRA_ARGS const char * a, int b, int c) {
b = GET_EXTRA + c; /* Just as example */
SET_EXTRA(b+c);
}
As you can see, the foo function has no distracting "#ifdefs", and it compiles in any platform.

How to use the pointer of a function in C? (No C++)

As the title says, how do I use the pointer of a function in C? Can I just take the address of the function name and pass it to another function; then dereference it and call it?
Thanks a lot.
If you know the function address, then yes. For example:
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int operation(int (*op)(int, int), int a, int b)
{
return op(a, b);
}
Then just call it like this:
printf("%d\n", operation(&add, 5, 3)); // 8
printf("%d\n", operation(&sub, 5, 3)); // 2
You can even do some array tricks:
int op = 0;
int (*my_pointer[2])(int, int) =
{
add, // op = 0 for add
sub // op = 1 for sub
};
printf("%d\n", my_pointer[op](8, 2)); // 10
well to answer your question precisely, there is a provision in C for such needs which is called "function pointer".
But you have to follow certain rules,
1) All the functions you want to call using function pointer must have same return type.
2) All the functions you want to call using function pointer must have same no of arguments and argument types.
For example,
int add(int, int);
int sub(int, int);
for above two functions you can write function pointer as,
int (*operation)(int , int);
and you can use it just as described by Flavio Torbio.
hope it helps.....

Resources