Is this an appropriate use of void pointers?
This question is about the appropriateness of using void pointers in a particular implementation.
I have a relatively simple program that consists of an infinite loop. On each loop, the program iterates over a fixed range of constant values and calls a function on each value. The particular function which is called can be one of three available and is specified at run time by an argument. Before the infinite loop starts, there is a condition block which sets a functional pointer to a function based on the supplied argument. This way the condition logic only has to be run once and not on every iteration in every loop.
This I have implemented and it works well, but I want to keep state between each call to the function. My proposal is to store state in a struct and pass that struct when calling the function on each of the values. The problem is that each function requires a different struct to store a different set of values of its state and the prototype of all t开发者_StackOverflow社区hree functions must be compatible (for the function pointer). I intend to solve this by using a void pointer in the prototypes of the three functions, thus maintaining compatible prototypes but allowing me to pass a different struct to each function.
The question is; is my proposal an appropriate use of void pointers or is it introducing too much runtime dynamism and I should therefore rethink my approach?
Note: It is not possible to use static variables in each of the three functions as the structs also need to be available in the infinite loop as there is also some processing to be done before and after the range of values is iterated.
As long as you are careful to keep your calls type-correct, this is a fairly C-idiomatic way to accomplish what you describe.
You could gain some measure of type safety by using a union
:
typedef struct {
int a;
char *b;
} s1;
typedef struct {
double d;
int *e;
} s2;
typedef union {
s1 s1;
s2 s2;
} ocd;
typedef int (*daemon_function)(ocd *);
Then all your functions could be of type daemon_function
but take different arguments through ocd.s1
or ocd2.s2
. I'd tend to call all that a bunch of pointless busy-work though. A simple void*
would work just as well.
You could also include a magic number at the front of your structures and then the functions could check type safety by looking at the magic number and seeing if it was the right one:
#define MAGIC 0x4d475600L
typedef struct {
long magic;
/* ... */
} whatever;
And then:
int f(void *p) {
whatever *w = (whatever *)p;
if(w->magic != MAGIC) {
/* complain and go boom! */
}
/* ... */
}
I did the magic number trick all the time back in my Motif programming days, you pass around a lot of void*
pointers in Motif/Xt/X11 development.
Void pointers are a method to tell the c typing system that you want it to stop doing its job and trust you to not mess up. It is an appropriate use of a void *, the only issue is that you have lost access to any type checking that your compiler performs. You can potentially create some very bizarre and hard to diagnose bugs. If you are sure that you know what you are doing (you sound like you do) and if you have checked every single line of your code several times and are sure that there are no logical errors in it, then you should be fine.
void *
is quite idiomatic in C. Personally I use it prevalently, but whenever I do it, I tend to used tagged structures for safety, i.e. I put a unique type ID at the beginning of each structure to identify it.
Generally it is OK.
I really prefer using the void *
contexts but it looks like you want to avoid it.
Since you already have some code that parses the argument and choose the function, you can just select the function in a switch and call it explicitly for each iteration.
精彩评论