使用多参数函数作为回调函数

时间:2015-10-29 11:25:41

标签: c function-pointers

我在C中使用一个与系统相关的计时器(我无法更改其代码)。我可以使用此功能访问它,其中包括:

void start_timer(int duration, void (*callback)(void*), void* arg);

所以我可以给定时器一个回调函数及其void*参数。

我想用作回调的函数是:

void send_message(ipaddr* source, ipaddr* destination, char* message);

我无法直接将此功能提供给start_timer,因为它与void (*)(void*)所需的类型不匹配。由于C中不存在匿名函数,我无法使用此解决方案(但这是我想要做的):

start_timer(1000, void(*)(void* stuff){
    send_message(source, destination, message);
}, NULL);

所以我必须给这个函数命名:

void call_send_message(void* stuff) {
    send_message(source, destination, message);
}
start_timer(1000, &call_send_message, NULL);

使用send_message调用start_timer函数是否有更美妙的方法?

3 个答案:

答案 0 :(得分:5)

创建struct,如下所示:

struct args {
    ipaddr *source;
    ipaddr *destination;
    char *message;
};

并让您的send_message函数获取void*参数,然后您只需将其转换为struct args类型,然后就可以访问其成员。如果你不能编辑它,那么创建一个像你的例子一样的“包装器”:

所以基本上你的功能

void call_send_message(void* stuff) {
    send_message(source, destination, message);
}

变为

void call_send_message(void* stuff) {
    struct args *realstuff = (struct args *) stuff;
    send_message(realstuff->source, realstuff->destination, realstuff->message);
}

答案 1 :(得分:1)

1.建立数据结构来存储您的数据。

typedef struct Data {
  ipaddr *src;
  ipaddr *dst;
  char   *msg;
} Data;

2.创建一个与签名匹配的包装器并在send_message函数内调用:

void wrapper(void *args) {
  Data *data = (Data*) args;
  send_message(data->src, data->dst, data->msg);

}

3.如下所示调用包装器:

   start_timer(duration, &wrapper, your_data);

答案 2 :(得分:0)

void*是一种描述指向我们不知道类型的变量的指针的类型。您不能取消引用它,但可以将其强制转换为指向任何类型的指针(char*int*mydata* ...)。如果send_message只接受一个指针(任何类型)的参数,则不需要任何包装器:

void send_message(char* message); // only one pointer parameter

char* my_string = ...;
start_timer(1000, send_message, (void*)my_string);

但是,如果send_message接受多个参数,则必须使用包装器,因为send_message(此处为三个指针)所采用的参数与{{1}给出的参数明确不同(一个指针)。进入堆栈的大小不一样,所以这可能不起作用。

请参阅其他答案,了解如何在这种情况下传递参数。


修改: 实际上,如果start_timer采用的参数与指针的大小完全相同,则可能没有包装器。如果指针长度为4个字节,并且send_message已经采用了4个send_message变量,则可以通过将四个字节作为伪char指针来破解系统。但是,这特别难看,我建议你在这种情况下使用包装器。