How can I make a function return its own type in C?

Viewed 56

TL;DR What should the type of x be if x = x(); is valid in C?


The whole story:

I am working on a simple game with multiple scenes. At first my code looked like this:

enum {kSCENE_A, kSCENE_B} ecene = kSCENE_A;
int main() {
    while(1) {
        switch(scene) {
          case kSCENE_A:
            // Renders scene a
            // And possibly modifies `scene`
            break;
          case kSCENE_B:
            // Renders scene b
            // And possibly modifies `scene`
            break;
        }
    }
}

However the main function is too verbose. I extracted the rendering part into different functions, but the switch still makes the code ugly. I defined a scene_map for this:

typedef enum {
    kSCENE_A,
    kSCENE_B,

    kN_SCENES
} Scene;
Scene RenderSceneA();
Scene RenderSceneB();
int main() {
    Scene scene = kSCENE_A;
    Scene (*scene_map[kN_SCENES])();
    scene_map[kSCENE_A] = SceneA;
    scene_map[kSCENE_B] = SceneB;
    while(1) scene = scene_map[scene]();
}

But I wonder if it would be possible in C that I write the code in this, or some similar way:

SomeType RenderSceneA();
SomeType RenderSceneB();
int main() {
    SomeType scene = RenderSceneA;
    while(1) scene = scene();
}

So what type should SomeType be, or can I only use void * for it? If the latter is true, how can I write this code in a clear manner than demonstrated in the second code block?

1 Answers

Here's a solution that will solve the problem. Note that it uses void (*)(void) as a generic function pointer type, as opposed to void * which isn't guaranteed to work for function pointers:

#include <stdio.h>

void (*f(void))(void);
void (*g(void))(void);

void (*f(void))(void)
{
    printf("This is f.\n");
    return (void (*)(void)) g;
}

void (*g(void))(void)
{
    printf("This is g.\n");
    return (void (*)(void)) f;
}

#define SRCALL(p)   ((void (*(*)(void))(void)) p())

int main(void)
{
    void (*(*p)(void))(void);

    p = f;

    p = SRCALL(p);
    p = SRCALL(p);
    p = SRCALL(p);

    return 0;
}

The function pointer casts are ugly, so I encapsulated them in the macro SRCALL (self-ref-call). The output is:

This is f.
This is g.
This is f.
Related