function prototype with void* parameter

2.4k views Asked by At

I have two functions, each taking a pointer to a different type:

void processA(A *);
void processB(B *);

Is there a function pointer type that would be able to hold a pointer to either function without casting? I tried to use

typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};

but it didn't work (compiler complains about incompatible pointer initialization).

Edit: Another part of code would iterate through the entries of Ps, without knowing the types. This code would be passing a char* as a parameter. Like this:

Ps[i](data_pointers[j]);

Edit: Thanks everyone. In the end, I will probably use something like this:

void processA(void*);
void processB(void*);

typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};

...

void processA(void *arg)
{
  A *data = arg;
  ...
}
3

There are 3 answers

11
Eric Postpischil On BEST ANSWER

This can be done without casts by using a union:

typedef struct A A;
typedef struct B B;

void processA(A *);
void processB(B *);

typedef union { void (*A)(A *); void (*B)(B *); } U;

U Ps[] = { {.A = processA}, {.B = processB} };

int main(void)
{
    Ps[0].A(0); // 0 used for example; normally you would supply a pointer to an A.
    Ps[1].B(0); // 0 used for example; normally you would supply a pointer to a B.
    return 0;
}

You must call the function using the correct member name; this method only allows you to store one pointer or the other in each array element, not to perform weird function aliasing.


Another alternative is to use proxy functions that do have the type needed when calling with a parameter that is a pointer to char and that call the actual function with its proper type:

typedef struct A A;
typedef struct B B;

void processA(A *);
void processB(B *);

typedef void (*processor_t)();

void processAproxy(char *A) { processA(A); }
void processBproxy(char *B) { processB(B); }

processor_t Ps[] = { processAproxy, processBproxy };

int main(void)
{
    char *a = (char *) address of some A object;
    char *b = (char *) address of some B object;
    Ps[0](a);
    Ps[1](b);
    return 0;
}

I used char * above since you stated you are using it, but I would generally prefer void *.

7
Andrey Mishchenko On

If you typedef void (*processor_t)(); then this will compile in C. This is because an empty argument list leaves the number and types of arguments to a function unspecified, so this typedef just defines a type which is "pointer to function returning void, taking an unspecified number of arguments of unspecified type."

Edit: Incidentally, you don't need the ampersands in front of the function names in the initializer list. In C, a function name in that context decays to a pointer to the function.

0
Guido On

It works if you cast them

processor_t Ps[] = {(processor_t)processA, (processor_t)processB};

By the way, if your code is ridden with this type of things and switch's all over the place to figure out which function you need to call, you might want to take a look at object oriented programming. I personally don't like it much (especially C++...), but it does make a good job removing this kind of code with virtual inheritance.