I have some code that works, but I don't understand why. Here is the code in question:
struct SceneInterface *TitleAsScene = &(struct SceneInterface) {
.update = (void (*)(void *)) title_update,
.render = (void (*)(void *)) title_render,
};
I get the function pointer and designated initializer stuff, but what is the &(struct SceneInterface) part doing? Normally it means address of, but the thing in parentheses is a type, not a variable, so what is it pointing to? If it's returning a pointer to struct SceneInterface, then the left-hand side is already that, so I don't understand why it's needed and why I get a segmentation fault if I remove it.
Here is the full working code for reference:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct SceneInterface {
void (*update)(void *instance);
void (*render)(void *instance);
};
struct Scene {
void *instance;
const struct SceneInterface *interface;
};
struct Scene *scene_create(void *instance, struct SceneInterface *interface)
{
struct Scene *scene = (struct Scene *) malloc(sizeof(struct Scene));
scene->instance = instance;
scene->interface = interface;
return scene;
}
void scene_update(struct Scene *scene)
{
// return this if function has a return type
(scene->interface->update)(scene->instance);
}
void scene_render(struct Scene *scene)
{
(scene->interface->render)(scene->instance);
}
struct Boot {
double x;
};
struct Boot *boot_create(double sideLength)
{
struct Boot *boot = (struct Boot *) malloc(sizeof(struct Boot));
boot->x = sideLength;
return boot;
}
void boot_update(struct Boot *boot)
{
printf("boot update\n");
}
void boot_render(struct Boot *boot)
{
printf("boot render\n");
}
struct Title {
double radius;
};
struct Title *title_create(double radius)
{
struct Title *title = (struct Title *) malloc(sizeof(struct Title));
title->radius = radius;
return title;
}
void title_update(struct Title *title)
{
printf("title update\n");
}
void title_render(struct Title *title)
{
printf("title render\n");
}
int main(int argc, char **argv)
{
struct Boot *boot = boot_create(10.0);
struct Title *title = title_create(5.0);
struct SceneInterface *BootAsScene = &(struct SceneInterface) {
.update = (void (*)(void *)) boot_update,
.render = (void (*)(void *)) boot_render,
};
struct SceneInterface *TitleAsScene = &(struct SceneInterface) {
.update = (void (*)(void *)) title_update,
.render = (void (*)(void *)) title_render,
};
struct Scene *bootScene = scene_create(boot, BootAsScene);
struct Scene *titleScene = scene_create(title, TitleAsScene);
boot_update(boot);
scene_update(bootScene);
boot_render(boot);
scene_render(bootScene);
title_update(title);
scene_update(titleScene);
title_render(title);
scene_render(titleScene);
return 0;
}
The syntax you're referring to, with what appears to be a cast followed by an initializer list, is a compound literal. It creates a temporary object of the given type. The line in question is then taking the address of that temporary object an placing it in a pointer.
There's not much point however to using a compound literal here. The code could just as easily be written like this:
struct SceneInterface BootAsScene = {
.update = (void (*)(void *)) boot_update,
.render = (void (*)(void *)) boot_render,
};
struct SceneInterface TitleAsScene = {
.update = (void (*)(void *)) title_update,
.render = (void (*)(void *)) title_render,
};
struct Scene *bootScene = scene_create(boot, &BootAsScene);
struct Scene *titleScene = scene_create(title, &TitleAsScene);
There's another problem with this code however. Function pointers are being casted to a different type and subsequently called via that casted type. Calling a function through an incompatible function pointer type triggers undefined behavior.
The functions should be changed to accept a void *
argument and cast the argument to the appropriate type inside of the function.