我在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
函数是否有更美妙的方法?
答案 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)
typedef struct Data {
ipaddr *src;
ipaddr *dst;
char *msg;
} Data;
send_message
函数内调用:void wrapper(void *args) {
Data *data = (Data*) args;
send_message(data->src, data->dst, data->msg);
}
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
指针来破解系统。但是,这特别难看,我建议你在这种情况下使用包装器。