This C Code Feels Illegal Pt. 1
I needed a function pointer that points to a function which returns a function pointer of the identical signature that returns a function pointer of the identical… oh no.
This is not possible using strong type security. It is possible with void pointers. First, the functions that do work need to be written, but they also need to return a pointer to a function that… oh no. It’s a chicken or an egg scenario. One isn’t complete without the other, and this is extremely important to remember.
typedef struct {
const char *name;
} myStruct;
not_sure_what_this_is_yet* first_function(myStruct *reference) {
printf("In first function: %s\n", reference->name);
return second_function(reference);
}
Here, I already have a problem. To return second_function, it has to be declared or defined already.
typedef struct {
const char *name;
} myStruct;
// This is a forward declaration. It could be in a header file instead.
not_sure_what_this_is_yet* second_function(myStruct *reference);
not_sure_what_this_is_yet* first_function(myStruct *reference) {
printf("In first function: %s\n", reference->name);
return second_function(reference);
}
// second_function is defined somewhere here.
typedef struct {
const char *name;
} myStruct;
// This is a definition.
not_sure_what_this_is_yet* second_function(myStruct *reference) {
printf("In second function: %s\n", reference->name);
return NULL;
}
not_sure_what_this_is_yet* first_function(myStruct *reference) {
printf("In first function: %s\n", reference->name);
return second_function(reference);
}
I’ve chosen to return NULL as a sentinel value. This is will stop execution. Here is what a pointer to such functions looks like.
typedef void* (*state(myStruct *reference))(myStruct *reference);
- state – the name of my type definition
- (*state(myStruct *reference)) – it points to a function that accepts a myStruct pointer
- void* … (myStruct * reference) – it returns a pointer to a function which accepts a myStruct pointer
While it’s not the easiest to read, it allows me to write code such as this.
typedef struct {
const char *name;
} myStruct;
// Declare the pointer type before it can be used.
typedef void* (*state(myStruct *reference))(myStruct *reference);
myStruct container;
container.name = "Alice.";
state* second_function(myStruct *reference) {
printf("In second function: %s\n", reference->name);
return NULL;
}
state* first_function(myStruct *reference) {
printf("In first function: %s\n", reference->name);
return second_function(reference);
}
// Initialize the pointer
state *state_machine = first_function(&container);
// Call the function until it points to NULL.
while(state_machine != NULL) {
// Cast the returned pointer from null* to state*.
state_machine = (state*)state_machine(&container);
}
This is complicated, but it allows me to have the control flow logic inside specific functions rather than one giant function which has loops and other control elements. At any point inside each function, a new function can be queued up, the current stack can be rolled back releasing resources, and another function can be then put onto the stack space.