大家好,我目前正面临一个非常讨厌的问题:
我正在编写一个使用函数指针工作的回调管理器系统,现在我已经分配了一些其他非void函数指针的void函数指针,我已经意识到它不是实际上允许在C。
目前我正在考虑构建void指针,以便匹配我的每个回调的原型函数,但我无法理解如何实现强制转换。
它是否可行或是否应采用其他解决方案?
目前这些是我的回调容器及其typedef:
typedef void modbus_read_t(unsigned int uid, unsigned int address, unsigned int count, char* response);
typedef void modbus_write_t(unsigned int uid, unsigned int address, unsigned int *data, char* response);
typedef void system_read_t(unsigned int uid, unsigned int var_number, unsigned int count, char* response);
typedef void system_write_t(unsigned int uid, unsigned int var_number, struttura_system *storage, char* response );
void (*M_callbacks_r[3]) (unsigned int uid, unsigned int address, unsigned int count, char* response);
void (*M_callbacks_w[2]) (unsigned int uid, unsigned int address, unsigned int *data, char* response);
void (*P_callbacks_r[2]) (unsigned int uid, unsigned int var_number, unsigned int count, char* response);
void (*P_callbacks_w[2]) (unsigned int uid, unsigned int var_number, struttura_system *storage, char* response );
这是注册回调函数的原型:
void registerCallback(int systemType,int operationType, void (callback)(void*));
必须做的是将void (callback)(void*)
转换为上面的一个typedef。
答案 0 :(得分:2)
嗯,施法应该有效。 C标准允许在函数指针类型之间进行转换,唯一不应该做的是通过具有错误原型的函数指针调用函数,即在调用之前转换回正确的原型,以避免未定义的行为。
为了便于阅读,我们首先简化一下你的数组:
modbus_read_t* M_callbacks_r[2];
modbus_write_t* M_callbacks_w[2];
system_read_t* P_callbacks_r[2];
system_write_t* P_callbacks_w[2];
我不知道为什么你typedef
编辑了函数类型而不是函数指针类型,但我会继续使用它。
现在可以按如下方式实现registerCallback
:
void registerCallback(int systemType,int operationType, void (*callback)()) {
// .. determine array by system type and operation type
M_callbacks_r[0] = (modbus_read_t*)callback;
}
我从callback
原型中删除参数的原因是,在标准C中,空参数列表不传达有关预期参数的信息(与C ++相反,它明确表示“无参数”)。这样就可以在不需要强制转换的情况下注册回调。
正如您在评论中提到的那样,您正在构建-Wstrict-prototypes -Werror
。因此,空参数列表不适合您。因此,您只能像这样定义registerCallback
:
void registerCallback(int systemType,int operationType, void (*callback)(void))
请注意参数列表中的显式void
。在将回调函数传递给registerCallback
并将其强制转换回函数本身时,您需要转换回调函数。
registerCallback(type, op, (void(*)(void))func_cb);
附注:POSIX系统上保留_t
后缀。为了便携,最好不要用它来命名你的类型。