我想為同一個函式發送具有不同簽名的回呼。像這樣的東西:
#include <stdio.h>
#include <stdarg.h>
void a(int pa) {}
void b(int pb1, float pb2) {}
// exec implementation
int main() {
exec(a, 1);
exec(b, 1, 2.3);
}
我想過使用類似的東西:
void exec(void (*func)(...), ...) {
int arg1;
float arg2;
va_list valist;
va_start(valist, size);
arg1 = va_arg(valist, int);
if (size == 1) {
(*func)(arg1);
va_end(valist);
return;
}
arg2 = va_arg(valist, float);
if (size == 2) {
(*func)(arg1, arg2);
va_end(valist);
return;
}
}
但顯然它不起作用:(
uj5u.com熱心網友回復:
使回呼函式介面在提供給函式的資料方面靈活的通常解決方案是給回呼簽名一個void *引數(可能除了其他引數之外)。可以通過這樣的引數提供任意資料。像這樣的東西:
void exec(void (*func)(void *), void *data) {
func(data);
}
struct s2 {
int i;
float f;
};
void func1(void *data) {
int i = *(int *)data;
// ...
}
void func2(void *data) {
struct s2 s = *(struct s2 *)data;
// ...
}
int main(void) {
int i = 42;
struct s2 s = { .i = 17, .f = 3.14 };
exec(func1, &i);
exec(func2, &s);
}
但是,可以通過指定沒有原型的回呼型別來做更像您描述的事情,其中??回呼函式真正具有不同的簽名。在這種情況下,至少還有這些警告:
如果回呼函式本身是用原型定義的(應該如此),那么引數型別不應該是任何被默認引數提升所改變的型別。因此,指標,
ints,doubles,但不是floats 或short ints 或chars(不是詳盡的串列)。如果您想支持其他引數型別,則需要在呼叫函式之前轉換函式指標,如下所述。回呼函式不能是可變的。
如果前端是可變引數,則需要在運行時以某種方式告知引數的實際數量和型別。
此外,需要使用正確的引數顯式呼叫回呼函式,因此只能支持一組固定的預定回呼簽名。
例如,這可能看起來像這樣:
enum sig { INT, INT_DOUB };
void exec(void (*func)(/* no prototype */), enum sig cb_sig, ...);
void a(int pa) {}
void b(int pb1, double pb2) {}
int main(void) {
exec(a, INT, 1);
exec(b, INT_DOUB, 1, 2.3);
}
void exec(void (*func)(/* no prototype */), enum sig cb_sig, ...) {
va_list valist;
va_start(valist, cb_sig);
switch (cb_sig) {
case INT: {
int i = va_arg(valist, int);
func(i);
break;
}
case INT_DOUB: {
int i = va_arg(valist, int);
double d = va_arg(valist, double);
func(i, d);
break;
}
default:
assert(("Can't be reached", 0));
}
va_end(valist);
}
這可能會引發一些警告,例如關于不提供原型的函式宣告,以及關于呼叫(已宣告但)未原型化的函式。但是,由于您在執行呼叫時就知道簽名,因此您可以通過適當的強制轉換來擺脫后一種警告。例如,
// ...
case INT: {
int i = va_arg(valist, int);
((void (*)(int))func)(i);
break;
}
// ...
uj5u.com熱心網友回復:
您可以更改回呼以采用單個 va_list 引數:
void a(va_list args)
{
int pa = va_arg(args,int);
}
void b(va_list args)
{
int pb1 = va_arg(args,int);
double pb2 = va_arg(args,double);
}
并讓您的其他功能傳遞va_list下去。
void exec(void (*func)(va_list), ...)
{
va_list valist;
va_start(valist, func);
func(valist);
va_end(valist);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/520438.html
標籤:C变量参数打回来
