'void *' 到 'void (*) (bool)' 使用 C++ 编译器在 C 中编译文件的指针错误

'void *' to 'void (*) (bool)' Errors with pointers compiling files in c with a c ++ compiler

首先感谢正在阅读和回复的人。

这部分代码,是界面库gui的一部分,完全用c语言编写。

但我很想用 c 编译这些编写的文件,使用 c ++ 编译器能够集成到我正在用 wxwidgets 做的程序中。

在 c 文件中,我有几个函数调用具有作为参数的指向其他函数的指针。

 typedef struct {
      void (*fchd_ptr)(bool);   
      uint16_t xpos;         
      uint16_t ypos;          
        ...
        ...
}BUTTON_t;

void BT_SetHandler(BUTTON_t* ptr, void* fchd_ptr)
{
    if (ptr == NULL)
        return;

    ptr->fchd_ptr =  fchd_ptr;  // OK in C, ERROR In C++
}

当我尝试用 C++ 编译时,出现此错误。

ptr-> fkt_ptr = fkt_ptr;
// error: invalid conversion from 'void *' to 'void (*) (bool)' [-fpermissive]

如果我进行显式转换。

ptr-> fkt_ptr = (bool *) fkt_ptr;
// error: can not convert 'bool *' to 'void (*) (bool)' in assignment

欢迎任何帮助和解释如何解决。

你的显式转换是错误的。你转换为 bool *(指向类型 bool 的对象的指针),而实际上你应该转换为 void (*)(bool)(指向采用 bool 且不返回任何内容的函数的指针)。1

如果您将该行替换为

ptr->fchd_ptr = (void (*)(bool)) fchd_ptr;

它将在 C 和 C++ 中编译。


但是,如果可能,您应该尝试只用 C 语言编译 C 代码 - 虽然我们可能会让这件事起作用,但这两种语言并不总是完全兼容,您很可能 运行路上的麻烦。通常,可以将 C 代码与 C++ 部分分开编译。如果您在头文件中使用 extern "C",您可以简单地 link 将 C++ 对象和 C 对象放在一起,或者将 C 部分保存在单独的库中(静态或动态)。

此外,我建议重新编写 C API,以便在可能的情况下,它真正始终采用函数指针。通过 void * 别名是丑陋的,如果您传入错误的指针类型,可能会导致一些非常讨厌的错误和崩溃。


1 函数指针通常与对象指针有很大不同,是否允许在两者之间进行转换是由实现定义的。在这里,您需要一个指向函数的指针,而不是指向对象的指针(例如 bool* 将是指向类型 bool 的对象的指针),以便您稍后可以调用它。您可以在代码示例中看到 void (*fchd_ptr)(bool) 是您分配给的变量的声明,这使得 void (*)(bool) 成为它的类型。如果您发现符号有些混乱,cdecl.org 是处理那些来自 C 的复杂数组、指针和函数指针名称的好方法。

如果您更改函数的签名以接受与 ptr->fchd_ptr 期望的类型相匹配的函数指针。然后,您将不需要使用强制转换来完成作业。

根据您的问题,这将是:

void BT_SetHandler(BUTTON_t* ptr, void (*fchd_ptr)(bool))

但是,如果您不确定 ptr->fchd_ptr 的类型是什么,您可以让编译器为您解决。以前,这只能通过模板函数来完成,它会根据在编译时传递给函数调用的内容派生出一个类型。但是,C++.11 provdes decltype,它允许您为函数参数强制执行您想要的类型,而不是让编译器从函数的调用者中推导出一个类型。

void BT_SetHandler(BUTTON_t* ptr, decltype(ptr->fchd_ptr) fchd_ptr)

只要您打算使用 C++ 编译器编译您的代码,这很好。