【发布时间】:2020-08-23 21:57:57
【问题描述】:
在下面的代码中 float 或 double 参数不起作用,值总是错误的。整数和字符串按预期工作。
除非有人能发现问题,否则我将放弃这个结构并尝试其他方法。
typedef void(*varfunc)(...);
typedef void(*invokefunc)(int, ...);
varfunc func_table[2];
void register_func(int slot, varfunc cb)
{
func_table[slot] = cb;
}
void invoke_func(int slot, void* a1, void* a2, void* a3, void* a4)
{
func_table[slot](a1, a2, a3, a4);
}
void func_1(float a, int b)
{
printf("%f %d", a, b);
}
void func_2(const char* c)
{
printf("%s", c);
}
int main()
{
register_func(0, (varfunc)func_1);
register_func(1, (varfunc)func_2);
((invokefunc)invoke_func)(0, 1.23f, 456);
((invokefunc)invoke_func)(1, "hello world");
return 0;
}
【问题讨论】:
-
对我来说,这看起来好像根本不应该工作。您必须使用来自
<stdarg.h>的va_...宏访问可变参数。 (这可能就是你实现你的想法的方式:让varfunc以va_list作为参数。但我真的看不到这种设计的好处。可变参数函数意味着你失去了类型安全,如果你把插槽弄混了,func_2很可能会崩溃。) -
这很有效,我在公共图书馆看到过类似的结构。不幸的是 va_list 需要传递许多参数,并用这个想法打破了整个观点。我对类型安全的看法是,类型安全在 C 中没有任何作用,这取决于程序员的类型安全和了解数据。
-
好吧,如果我从
varfunc定义中删除...,它会按照您的描述工作。顺便说一句,您不必使用va_list传递参数的数量。但是,...之前必须至少有一个 names 参数,但这不适用于va_list参数。而且您在需要它的函数中确实有一个参数,即插槽 id。 Here's 怎么会这样。浮点数被正确打印。 -
是的,你说得对,这可以工作。但在那种情况下,我需要某种包装器来解包正确的参数并调度回调。这与我现在所拥有的类似,除了我为每种类型的函数调用使用参数结构而不是 va_list。但我一定会尝试像你建议的那样。谢谢。
-
您不需要包装器,但您必须根据
va_list实现回调,您必须从中“解包”值。 (这有点像在 Perl 5 中shifting 来自@_的子参数。)无论如何,祝你好运。
标签: c callback arguments variadic