函数指针与void和非void指针参数之间的转换

时间:2014-07-15 11:50:44

标签: c gcc function-pointers void-pointers

我有一个与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;
}

就是这样,该程序由两部分组成,mainmodulemodule输出文本,但它不应该处理所有输出细节 - 相反,main是处理输出的那个。由于main依赖于module而不是modulemain不知道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的错误还是我错过了什么?

1 个答案:

答案 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*)不是兼容的类型。