具有可变参数化和类型的 C 函数指针

C function pointers with variable parameterisation and type

我正在开发一个用 C 语言编写的游戏引擎,尽可能少地使用标准库。对于我在游戏中的“对象”,我有自己的“抽象”结构版本,让人想起 Java 和 C# 等面向对象的语言,但是当涉及到对象做事时我遇到了问题,即它们包含一组功能。有没有一种方法可以存储(作为结构的成员)具有可变大小、类型和参数化的函数指针数组?我是否可以只放弃其中一个要求,即具有 void 类型的所有操作功能?还是我应该完全回到绘图板?我假设这也必须动态分配,但据我所知这是这类事情的标准,对吧?提前致谢

您可以安全地将任何函数指针转换为任何其他函数指针类型,只要您在调用它之前将其转换回正确的类型 (C17 6.3.2.3.8)。因此,例如,您可以将 void (*)(void) 指针数组作为 table 函数。您可以像任何其他数组一样动态分配它。请注意,指向此类数组的指针将具有“指向函数指针的指针”类型。

许多人发现使用 typedef 有助于减少 C 函数指针语法的混乱。

typedef void (*funcptr_v_v)(void);
typedef double (*funcptr_d_ii)(int, int);
typedef char *(*funcptr_cp_i)(int);

struct foo {
    funcptr_v_v *table;
};

double my_d_ii(int x, int y) { ... }
char *my_cp_i(int z) { ... }

struct foo f;
f.table = malloc(10 * sizeof(funcptr_v_v));
f.table[0] = (funcptr_v_v)my_d_ii;
f.table[1] = (funcptr_v_v)my_cp_i;
// ...
printf("Calling my_cp_i(7), returning %s\n", ((funcptr_cp_i)(f.table[1]))(7));

如果你想在没有 typedef 的情况下定义 struct foo,它看起来像

struct foo {
    void (**table)(void);
};

当然,您可以通过某种方式跟踪存储在 f.table[1] 中的函数指针实际上指向一个接受一个 int 参数和 returns char *,调用的时候正确投回去。无法在运行时测试类型。如果你应该将它转换为一个与它指向的函数不匹配的类型,并以这种方式调用它,编译器可能不会阻止你,但事情可能会在运行时崩溃。因此,您需要以一种不易出错的方式设计代码。

“性能可行”并不是真正可以回答的;在您进行测试之前,无法知道您的性能需求或瓶颈是什么。但是创建和释放这样的数组并不比任何其他类型的动态数组更昂贵或更少,并且通过指针调用函数通常只比直接调用它稍微慢一点,如果有的话。