'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++ 编译器编译您的代码,这很好。
首先感谢正在阅读和回复的人。
这部分代码,是界面库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++ 编译器编译您的代码,这很好。