我在C ++中定义了两种类型的函数指针,看起来像这样:
typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
typedef std::function<void(std::string)> LogFunction;
Class Core{
...
void myfunc1(LogFunction lg1, CallbackFn callback, int x, std::string y);
};
并且我希望能够用C公开它们,但我似乎找不到找到这种方法的方法。我的第一个尝试是将其转换为void*
,然后将其重铸为实际类型。但这似乎是个坏主意。因此,我对如何进行这种转换一无所知。另外,我至少需要使用C ++ 11来解决这个问题。
非常感谢您的回答。但是,我需要添加一些解释。我了解extern "C"
,实际上C++
中已经公开了此功能。但是,我遇到的问题是在C和C ++之间来回传递函数指针。一种方法是以C可以直接使用的方式定义函数指针。例如,我需要更改:
DLL
与其兼容的C语言:
typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
typedef std::function<void(std::string)> LogFunction;
并改为使用这些。但是,这样做的缺点是C ++客户端也使用DLL,这将是将C ++的所有内容都更改为与C兼容的障碍,这样做会使我失去C ++的优势。相反,我虽然提出了第二种方法。 C ++保持不变,但是对于C链接以及通过C API与其他语言的交互,我自己进行转换。那就是他们使用C样式,然后在实现部分将其转换回C ++。为了进一步简化此操作,因此我还为C ++部分设计了一些默认值。意思是,假设缺少一个更好的例子,该实例需要一个回调函数来记录发生的任何事情。我定义了一个回调函数,以防用户未提供它,并为C API创建两个函数,具体类似于以下内容:
typedef void(*CCallbackFn)(bool, char*, int, unsigned char, int length);
typedef void(*CLogFunction)(char* string, int length);
例如,客户端可以使用get_default_log_callback并使用其返回到//in core.cpp for example
include "Core.h"
...
extern "C"
{
Core * core;
...
Core_API void* get_default_log_callback()
{
return (void*) core->SomeDefaultCallback();
}
Core_API void* set_log_callback(void* fn)
{
// convert/cast that to the c++ callback type
// CallbackFn,
core->SetCallback(fn_converted);
}
。基本上,这里的想法是能够使用C ++已经定义的资产。我陷入了这种转换过程,如何将此类回调指针转换为C兼容类型(就像我展示的那样,例如,将指针强制转换为void *并编写一个接受void *的C包装器真的很容易然后将其重铸为正确的类型。
我也想知道这种情况,以及这是一种好习惯还是一种不好的做法。
[我还想知道是否可以从set_log_call_back
和CCallbackFn
中进行转换?假设我有一个CallbackFn
形式的函数(例如,我的C函数),但我想最终使它成为CCalbackFn
形式(更改它并调用接受CallbackFn
的底层C ++)?这可能吗 ?
我在C ++中定义了两种类型的函数指针,如下所示:typedef void(* CallbackFn)(bool,std :: string,py :: array_t
C不会/不能处理C ++名称修改(也不能处理与C类型不同的C ++类型)。您不能在暴露给C的任何东西中使用非POD类型(以及普通函数指针涉及在C中不可用的类型)。并且您需要对暴露的东西使用CallbackFn
,以禁用名称修饰(或更确切地说,使用任何命名约定) /修改您当前使用的C编译器平台)。
您可以通过声明extern "C"
将函数公开给C。
为了将任何C ++函数公开给C,您应该将C ++调用包装在纯C ++库中的C函数中。并仅从中导出C函数。对库内部和外部的C函数声明使用通用标头。这些函数可以在任何C环境中调用。所有C ++类型都包装在一个类中,并跨函数包装传递指向该类的指针,作为C ++环境的句柄。指向类的指针应为void *或仅长。而且只有在C ++方面,您才能将其重新解释为自己的环境类。更新1: