Function pointer pointing to functions with different number of arguments - c

How to handle assignment of the functions to one function pointer, each with different number of parameters ? The problem is that parameters differ in number and type. If possible give an example.

Function pointers can be cast in the same way as the other pointers. You will have a generic function pointer (similar to void * for storage types), and use it to hold/pass the address of the function. Before calling the function, you will need to cast it to the correct type.
Here is a working example:
#include <stdio.h>
typedef void (*generic_t)(void);
typedef int (*type2_t)(int);
typedef int (*type3_t)(int, char *s);
void test1(void) {
printf("Test 1\n");
}
int test2(int i) {
printf("Test 2 %i\n",i);
return i;
}
int test3(int i, char *s) {
printf("Test 3 %i, %s\n", i, s);
return i++;
}
int main(void) {
generic_t f1, f2, f3;
f1 = &test1;
f2 = (generic_t)&test2;
f3 = (generic_t)&test3;
f1();
int i = ((type2_t)f2)(10);
i = ((type3_t)f3)(20,"This is test");
}
In addition, you will need to implement a mechanism to recognize what is the type of function that the pointer is pointing to. One approach is to use a struct that holds the pointer and the enum of the type.

Another possibility is to create a union of different function pointer types:
union funptr {
void (*v)();
void (*vi)(int);
void (*vs)(char *);
int (*i)();
int (*ii)(int);
int (*iii)(int, int);
int (*is)(char *);
};

You can use void pointers to pass reference to the in and out parameters. Multiple parameters and return values you can wrap in the structs. The return value may return status.
Sometimes it used in low-level device drivers.
typedef int func(void *, void *);
func *fptr;
struct s1
{
int i;
char *s;
};
int test1(void *in, void *out)
{
printf("Test 1\n");
return 0;
}
int test2(void *in, void *out)
{
int *i = in;
printf("Test 2 %i\n", *i);
return *i;
}
int test3(void *in, void *out)
{
struct s1 *s = in;
printf("Test 3 %i, %s\n", s -> i, s -> s);
return ++s -> i;
}
int main(void)
{
fptr = test1;
fptr(NULL, NULL);
fptr = test2;
fptr((int[]){10}, NULL);
fptr = test3;
printf("Returned value: %d\n", fptr(&(struct s1){20,"This is test"}, NULL));
}

You have to declare a new function pointer type for every different signature that you need to handle.

Related

returning void* for a function/method return

Is it possible to have a function in C return a 'dynamic' return type
example
printResult (NumOrChar());
void* NumOrChar(void) {
// return int or char
}
void printResult (void* input) {
if (isdigit(input)) {
printf("It's a number");
}
else {
printf("It's not a number");
}
Functions can certainly return void *. But that is a specific pointer type with properties that make it suitable for conveying pointers to objects of any type. It is not a general-purpose wildcard type. Moreover, it does not carry any kind of information about the actual type, if any, of the object to which it points, so there is no way to determine that type dynamically. A C++ programmer might describe this situation as C not providing any RTTI.
Instead, you can return a type that can convey objects of a variety of types, known in advance, with a mechanism to discriminate among those. For example,
union num_or_string {
struct { _Bool is_num; };
struct { _Bool _x1; int num; };
struct { _Bool _x2; char *string; };
};
union num_or_string NumOrChar(void) {
// return a union num_or_string containing an int or a char *
}
void printResult (union num_or_string) {
if (num_or_string.is_num) {
printf("It's a number: %d\n", num_or_string.num);
} else {
printf("It's a string: %s\n", num_or_string.string);
}
}
You can use _Generic in some circumstances
int func_int(int *p)
{
printf("%s\n", __FUNCTION__);
return 5; /* does not make too much sense */
}
float func_float(float *p)
{
printf("%s\n", __FUNCTION__);
return 5.0f; /* does not make too much sense */
}
double func_double(double *p)
{
printf("%s\n", __FUNCTION__);
return 5.0; /* does not make too much sense */
}
#define func(p) _Generic((p), \
int *: func_int, \
float *: func_float, \
double *: func_double)(p) \
Instead of having a block of ifs, one can use a structure of function pointers as a virtual table, including to_string. The following dynamically creates the Type, which can be Num or Letter.
#include <stddef.h> /* offsetof */
#include <stdio.h> /* [|s|sn]printf, fgets, stdin */
#include <stdlib.h> /* malloc, free, strtol */
#include <ctype.h> /* isdigit */
#include <errno.h>
#include <assert.h>
struct Type;
typedef void (*TypeToString)(const struct Type *const, char (*const)[32]);
typedef void (*TypeAction)(struct Type *const);
struct Type {
const struct TypeVt *vt;
};
/* Num extends Type. */
struct Num {
struct Type base;
int value;
};
static struct Num *num_upcast(struct Type *const type) {
return (struct Num *)(void *)((char *)type - offsetof(struct Num, base));
}
static const struct Num *const_num_upcast(const struct Type *const type) {
return (const struct Num *)(const void *)((const char *)type
- offsetof(struct Num, base));
}
static void num_to_string(const struct Type *const type, char (*const a)[32]) {
const struct Num *const num = const_num_upcast(type);
snprintf(*a, sizeof *a, "%d", num->value); /* C99. */
}
static void num_delete(struct Type *const type) {
struct Num *const num = num_upcast(type);
free(num);
}
/* Letter extends Type. */
struct Letter {
struct Type base;
char letter;
};
static struct Letter *letter_upcast(struct Type *const type) {
return (struct Letter *)(void *)((char *)type
- offsetof(struct Letter, base));
}
static const struct Letter *const_letter_upcast(const struct Type *const type) {
return (const struct Letter *)(const void *)((const char *)type
- offsetof(struct Letter, base));
}
static void letter_to_string(const struct Type *const t, char (*const a)[32]) {
const struct Letter *const letter = const_letter_upcast(t);
sprintf(*a, "%c", letter->letter);
}
static void letter_delete(struct Type *const type) {
struct Letter *const letter = letter_upcast(type);
free(letter);
}
static const struct TypeVt {
const char *name;
const TypeToString to_string;
const TypeAction delete;
} num_vt = { "num", &num_to_string, &num_delete },
letter_vt = { "char", &letter_to_string, &letter_delete };
static void type_to_string(const struct Type *const t, char (*const a)[32]) {
assert(t);
t->vt->to_string(t, a);
}
static void type_delete(struct Type *const t) {
assert(t);
t->vt->delete(t);
}
static struct Type *num(const int value) {
struct Num *num = malloc(sizeof *num);
if(!num) return 0;
num->base.vt = &num_vt;
num->value = value;
return &num->base;
}
static struct Type *letter(const char letter) {
struct Letter *l = malloc(sizeof *l);
if(!l) return 0;
l->base.vt = &letter_vt;
l->letter = letter;
return &l->base;
}
static struct Type *read_type(void) {
struct Type *type;
char buffer[64];
if(!fgets(buffer, sizeof buffer, stdin)) return 0;
if(isdigit(buffer[0])) {
long n;
errno = 0;
n = strtol(buffer, 0, 0);
if(errno) return 0;
type = num(n);
} else {
type = letter(buffer[0]);
}
return type;
}
int main(void) {
char a[32];
struct Type *type = 0;
int is_success = 0;
do {
if(!(type = read_type())) break;
type_to_string(type, &a);
printf("\"%s\" is of type %s.\n", a, type->vt->name);
is_success = 1;
} while(0); {
if(type) type_delete(type);
}
if(!is_success) return perror("Failure"), EXIT_FAILURE;
return EXIT_SUCCESS;
}
Probably overkill for your function, but as one has more types, this becomes increasingly attractive. One can consider a union of similar spaced types so that it could be allocated entirely on the stack.
$ bin/numorchar
524645 3456542563456
"524645" is of type num.
$ bin/numorchar
6245635724564357652654245634576
Failure: Result too large
$ bin/numorchar
ata gfddsgsdg
"a" is of type char.
$ bin/numorchar
"
" is of type char.
I guess you are speaking about the C# feature (according to my Google search).
In C, it's not possible unless doing it yourself (other answers show examples). It can be easy or hard depending of your needs. You should think about switching to another language if you really want this (they are sometimes called variants in them).

How to make a function which receive other function as param (with no known parameters)

Previously I asked How to make a function which receive a function as param in C language. I get an answer Link to the question but this solution is based on the parameters of argument's function. I mean:
int functionToPassAsParameter (int arg1, int arg2){
// do something
}
int functionWhichReceiveFunction (int (*f)(), int arg1, int arg2){
// do something
f(arg1, arg2);
// do something
}
// How to call the function
functionWhichReceiveFunction (&functionToPassAsParameter, 1, 2);
I would like something like:
int functionToPassAsParameter (int arg1, int arg2){
// do something
}
int functionWhichReceiveFunction ( f() ){
// do something
f();
// do something
}
// How to call the function
functionWhichReceiveFunction ( functionToPassAsParameter(arg1, arg2) );
So, when I call the function, I pass the correctly params but when I define the function which receive the other function I do not specify which params I will send to it. Is that possible to make?
EDIT 1:
I wanna achieve pass any function to functionWhichReceiveFunction. Something like:
int function_a (int param1, int param2) { /* Do something */ };
void function_b (char *arg1) { /* Do something */ };
// Call the function with two differents functions regardless return type nor params
int x = functionWhichReceiveFunction ( function_a(param1, param2) );
functionWhichReceiveFunction ( function_b(arg1) );
Define the function to be passed to take a void * as a parameter. That way the function that calls the given function doesn't need to know anything specific about the parameters:
struct params1 {
int arg1;
int arg2;
};
struct params2 {
char *arg1;
char *arg2;
};
int functionToPassAsParameter (void *param){
struct params1 *args = params;
// do something
}
int otherFunctionToPassAsParameter (void *param){
struct params2 *args = params;
// do something
}
int functionWhichReceiveFunction (int (*f)(void *), void *args) {
// do something
f(args);
// do something
}
struct params1 p1 = { 1, 2 };
functionWhichReceiveFunction (&functionToPassAsParameter, &p1);
struct params2 p2 = { "abc", "def" };
functionWhichReceiveFunction (&otherFunctionToPassAsParameter, &p2);
To be able to pass a function with unknown parameters to a function, declare the function that will pass the function as follows:
int g(int (*f)());
The function that is actually passed can have any number of parametes, for example:
int f(int x, void *y);
The call is now as follows:
g(f);
The above means that g passes f, which can have zero or more parameters of any type. This is denoted by the empty parameter list.
A particular function that may need to be passed is for example f.
Now g is called with function f, or any other function.
Note that it is up to g to know which parameters must be passed in calling f. So you need a "protocol" that tells g which function/type is passed. For example, besides passing the function, pass an identifier (int) that says what type of function is passed, for example:
#define fS_I_I 1 // f needs String, int, Int
#define fD_I 2 // f needs Double, Int
#define fI_I 3 // f needs Int, Int
int g(int ID, int (*f)());
g(fI_I, f);
Learn more about closures and tagged unions. Notice that C don't have them. You might want to emulate that with callbacks
I wanna achieve pass any function to functionWhichReceiveFunction
You cannot do that simply and portably. Remember that the signature of a function in C is related to its calling conventions (so to the ABI used by your compiler and your code; for examples, look into Linux x86 ABIs; so floating point arguments could be passed in different registers as integral arguments, so your compiler needs to know the signature of all your function pointers). You need to also give to functionWhichReceiveFunction something which describes the signature.
What you might consider doing, assuming your platform have function pointers of the same size and in the same address space as data pointers (this is very often the case), is to pass to functionWhichReceiveFunction a void* pointer (actually, a function pointer casted to void*) and an enumeration describing it.
For example
enum funsig_en {
funsig_void_to_void,
funsig_int_to_void,
funsig_int_to_double,
funsig_int_double_to_void,
};
Then, you'll have corresponding function signatures (types)
typedef void fun_void_to_void(void);
typedef void fun_int_to_void(int);
typedef double fun_int_to_double(int);
typedef void fun_int_double_to_void(int, double);
Suppose you have these static functions
static void statf_void_to_void(void);
static void statf_int_to_void(int);
static double statf_int_to_double(int);
static void statf_int_double_to_void(int, double);
You might declare
void
functionWhichReceiveFunction (void*res, enum funsig_en sigkind, void*fun, ...);
and you could use it as
functionWhichRecieveFunction(NULL, funsig_void_to_void
(void*)statf_void_to_void);
or
functionWhichRecieveFunction(NULL, funsig_int_to_void,
(void*)statf_int_to_void, 123);
or
double r = 0;
functionWhichRecieveFunction(&r, funsig_int_to_double,
(void*)statf_int_to_double, 2345);
I leave you to code that variadic functionWhichRecieveFunction. You need stdarg(3) facilities. It would include code like
va_args arglist;
va_start (arglist, fun);
switch(sigkind) {
case funsig_int_to_void: {
int a = va_arg(arglis, int);
fun_int_to_void* fptr = (fun_int_to_void*)fun;
(*fptr)(a);
return;
} // end case funsig_int_to_void
much later you'll need some va_end(arglis); near the end of your functionWhichRecieveFunction body.
Another possibility is using varargs. In the following example every function being called does its own interpretation of parameters.
#include <stdio.h>
#include <stdarg.h>
// expects 4 arguments (int, int, int, char*)
void f1(va_list args) {
int a, b, c;
char *d;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, int);
d = va_arg(args, char *);
printf("%d, %d, %d: %s\n", a, b, c, d);
}
// expects 3 ars (int, int, char*);
void f2(va_list args) {
int a, b;
char *c;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, char *);
printf("%d, %d: %s\n", a, b, c);
}
void caller(void (*f)(va_list), ...) {
va_list args;
va_start(args, f);
f(args);
va_end(args);
}
int main() {
caller(&f1, 0, 1, 3, "hello");
caller(&f2, 1, 2, "bye");
return 0;
}
Another possibility is to have caller to interpret parameters based on some type info and call a correct function call. This might be useful if you have a limited number of argument patterns and just regular functions to call:
void f3(int a, int b, int c, char *d) {
printf("%d, %d, %d: %s\n", a, b, c, d);
}
void f4(int a, int b, char *c) {
printf("%d, %d: %s\n", a, b, c);
}
typedef enum {
type1, type2
} Types;
void caller1(Types t, void (*f)(), ...) {
va_list args;
va_start(args, f);
switch (t) {
case type1: {
int a, b, c;
char *d;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, int);
d = va_arg(args, char *);
f(a,b,c,d);
break;
}
case type2: {
int a, b;
char *c;
a = va_arg(args, int);
b = va_arg(args, int);
c = va_arg(args, char *);
f(a,b,c);
}
}
va_end(args);
}
int main() {
caller1(type1, &f3, 3,2,1, "hi");
caller1(type2, &f4, 3,2,"take care");
return 0;
#Paul Ogilvie, this is the code:
int f(int x, void *y) {
return x;
};
int g(int (*f)()) {
int x = f(1, NULL); // call f with parameters
printf("X is: %d", x);
return(x); // return result
};
int main()
{
//g( f(1, 2) ); // this passes the result of a call to f, not f
g( f ); // this passes f
return 0;
}

Parameter passing multiple values using void pointer

I want to pass multiple arguments to a function using a void pointer.
void* function(void *params)
{
//casting pointers
//doing something
}
int main()
{
int a = 0
int b = 10;
char x = 'S';
void function(???);
return 0;
}
I know that I have to cast them to a certain variable in my function but I do not know how I can pass my 3 arguments as one void pointer to my function.
I have searched for this problem know quite some time but I could not find anything that would help me.
You could do it like this:
struct my_struct
{
int a;
int b;
char x;
}
void * function(void * pv)
{
struct my_strcut * ps = pv; /* Implicitly converting the void-pointer
/* passed in to a pointer to a struct. */
/* Use ps->a, ps->b and ps->x here. */
return ...; /* NULL or any pointer value valid outside this function */
}
Use it like this
int main(void)
{
struct my_struct s = {42, -1, 'A'};
void * pv = function(&s);
}
Following up on the OP's update:
struct my_struct_foo
{
void * pv1;
void * pv2;
}
struct my_struct_bar
{
int a;
int b;
}
void * function(void * pv)
{
struct my_strcut_foo * ps_foo = pv;
struct my_struct_bar * ps_bar = ps_foo->pv1;
/* Use ps_foo->..., ps_bar->... here. */
return ...; /* NULL or any pointer value valid outside this function */
}
Use it like this
int main(void)
{
struct my_struct_bar s_bar = {42, -1};
struct my_struct_foo s_foo = {&s_bar, NULL};
void * pv = function(&s_foo);
}
The void* is used as a pointer to a "generic" type. Hence, you need to create a wrapping type, cast convert to void* to invoke the function, and cast convert back to your type in the function's body.
#include <stdio.h>
struct args { int a, b; char X; };
void function(void *params)
{
struct args *arg = params;
printf("%d\n", arg->b);
}
int main()
{
struct args prm;
prm.a = 0;
prm.b = 10;
prm.X = 'S';
function(&prm);
return 0;
}

Passing an argument to function pointer

I just can't figure out how to pass an Argument like in the following scenario:
#include<stdio.h>
void quit(const char*);
int main(void){
const char *exit = "GoodBye";
void (*fptr)(const char*) = quit;
(*fptr)(exit);
return 0;
}
void quit(const char *s){
printf("\n\t%s\n",s);
}
This is how my program should work and it does, but when I make a text menu i just can't figure out how to do it:
#include<stdio.h>
#include<stdlib.h>
int update(void);
int upgrade(void);
int quit(void);
void show(const char *question, const char **options, int (**actions)(void), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void){
printf("\n\tQuit...\n");
return 0;
}
void show(const char *question, const char **options, int (**actions)(void), int length){
int choose = 0, repeat = 1;
int (*act)(void);
do{
printf("\n\t %s \n",question);
for(int i=0;i<length;i++){
printf("%d. %s\n",(i+1),options[i]);
}
printf("\nPlease choose an Option: ");
if((scanf("%d",&choose)) != 1){
printf("Error\n");
}
act = actions[choose-1];
repeat = act();
if(act==0){
repeat = 0;
}
}while(repeat == 1);
}
Here I need to change the quit function (int quit(void); to int quit(char *s){};) like in the First example and call it with an argument like const char *exit = "GoodBye"; ==>> (*fptr)(exit);
I know that at this point my program takes only void as argument, but I done it only to illustrate the problem.
I'm very confused about this.
EDIT:
this int (*actions[3])(void) I think is an Array of Function pointers and all 3 function pointers takes void as argument, but I need to know if i can use one pointer to take an argument or i have to re-code the whole program.
Since you have an array of function pointers, all the functions need to be of the same type. So at the very least each function should take a const char * (not all functions need to use it) and the array type should be changed to match.
If you want something more flexible, you can have the functions accept a single void * so each function can be passed a different parameter which it then casts to the appropriate type. This is how pthreads passes parameters to functions which start a new thread. You will lose some compile-time type checking with this, so be careful if you go this route.
EDIT:
An example of the latter:
#include<stdio.h>
#include<stdlib.h>
int update(void *);
int upgrade(void *);
int quit(void *);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void *) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void *unused){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void *unused){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void *message){
printf("\n\tQuit...%s\n", (char *)message);
return 0;
}
void show(const char *question, const char **options, int (**actions)(void *), int length){
...
if (act == quit) {
repeat = act("GoodBye");
} else {
repeat = act(NULL);
}
...
}
Since you are using a an array of function pointers, you don't know which ones to take which arguments. But have You can avoid re-coding it by making the functions to take "unspecified number of arguments". i.e. Remove the void from as the parameter from function definitions and prototypes from of the function pointers and from the quit() function.
int quit(const char*);
void show(const char *question, const char **options, int (**actions)(), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])() = {update,upgrade,quit};
...
}
int quit(const char *msg){
printf("\n\tQuit...%s\n", msg);
return 0;
}
void show(const char *question, const char **options, int (**actions)(), int length){
....
int (*act)();
....
}
This works because C allows a function with no explicit parameters to take "unspecified number of arguments". Otherwise, you need to make all functions have similar signatures.

Why do I see redefinition error in C?

Following is my code, I am trying to run it in Visual Studio.
#include <stdio.h>
#include <conio.h>
int main()
{
//int i;
//char j = 'g',k= 'c';
struct book
{
char name[10];
char author[10];
int callno;
};
struct book b1 = {"Basic", "there", 550};
display ("Basic", "Basic", 550);
printf("Press any key to coninute..");
getch();
return 0;
}
void display(char *s, char *t, int n)
{
printf("%s %s %d \n", s, t, n);
}
It gives an error of redefinition on the line where opening brace of function is typed.
You call display before declaring it, and in such cases the compiler assumes the return type is int, but your return type is void.
Declare the function before using it:
void display(char *s, char *t, int n);
int main() {
// ...
Also note, that you declare it as receiving char*, but pass string literals to it (const char*) either change the declaration, or change the arguments, e.g:
void display(const char *s, const char *t, int n);
int main()
{
// snip
display ("Basic", "Basic", 550);
//snap
}
void display(const char *s, const char *t, int n)
{
printf("%s %s %d \n", s, t, n);
}

Resources