我有一个与void指针转换相关的问题。我不是在void *和非void指针之间进行转换,而是在函数指针类型之间进行转换,其中一个函数指针类型为void*
,另一个指针指向某个特定数据类型。
以下是允许重现警告消息的代码:
#include <stdio.h>
typedef void (*module_outputMessage)(void *param, const char *msg);
void module_function(module_outputMessage outputFunc, void *output_param, int msgid, const char *msg1, const char *msg2)
{
if (msgid == 0)
outputFunc(output_param, msg1);
else
outputFunc(output_param, msg2);
}
struct main_state
{
int msgid;
};
void main_outputMessage(struct main_state *state, const char *str)
{
printf("Message %d: %s\n", state->msgid, str);
state->msgid++;
}
int main(int argc, char *argv[])
{
struct main_state state;
const char *msg1 = "abc", *msg2 = "def";
state.msgid = 0;
module_function(&main_outputMessage, &state, 0, msg1, msg2);
module_function(&main_outputMessage, &state, 0, msg1, msg2);
module_function(&main_outputMessage, &state, 1, msg1, msg2);
module_function(&main_outputMessage, &state, 0, msg1, msg2);
module_function(&main_outputMessage, &state, 1, msg1, msg2);
return 0;
}
就是这样,该程序由两部分组成,main
和module
。 module
输出文本,但它不应该处理所有输出细节 - 相反,main
是处理输出的那个。由于main
依赖于module
而不是module
,main
不知道module
中发生了什么,并且要输出消息,它需要一个输出函数作为参数传递。为了使输出知道它正在处理哪个状态对象,该对象需要与输出函数一起传递。这就是转换发挥作用的地方:main
不知道也不应该关心struct main_state*
的实现,因此它不接受void*
作为函数参数,而是接受{{1}它仅传递给输出函数。
所以这一切归结为这些类型之间的转换:
void (*)(void* , const char*)
void (*)(struct main_state *, const char*)
该计划给出了预期的结果:
Message 0: abc
Message 1: abc
Message 2: def
Message 3: abc
Message 4: def
然而,GCC抱怨指针类型不兼容(我得到五条这样的消息,每个函数调用一条消息):
funcpointvoid.c: In function ‘main’:
funcpointvoid.c:33:2: warning: passing argument 1 of ‘module_function’ from incompatible pointer type
module_function(&main_outputMessage, &state, 0, msg1, msg2);
^
funcpointvoid.c:5:6: note: expected ‘module_outputMessage’ but argument is of type ‘void (*)(struct main_state *, const char *)’
void module_function(module_outputMessage outputFunc, void *output_param, int msgid, const char *msg1, const char *msg2)
^
所以尽管它对我来说很好,有了这些警告,我不确定这个'架构'是否可以依赖。但正如我自己看到的那样,唯一的区别是指向void和non-void的指针,而这只是使用泛型指针的一种方式,无论它们存在于何种目的。这是GCC的错误还是我错过了什么?
答案 0 :(得分:4)
void (*)(void* , const char*)
void (*)(struct main_state *, const char*)
是两种不同的类型,因为函数指针类型之间没有隐式转换,您需要使用强制转换使转换显式:
变化:
module_function(&main_outputMessage, &state, 0, msg1, msg2);
到
module_function((module_outputMessage) main_outputMessage,
&state, 0, msg1, msg2);
但请注意,函数调用outputFunc
在技术上会调用未定义的行为,因为void (*)(void* , const char*)
和void (*)(struct main_state *, const char*)
不是兼容的类型。