我如何在C中公开C ++函数指针?

问题描述 投票:4回答:3

我在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_backCCallbackFn中进行转换?假设我有一个CallbackFn形式的函数(例如,我的C函数),但我想最终使它成为CCalbackFn形式(更改它并调用接受CallbackFn的底层C ++)?这可能吗 ?

我在C ++中定义了两种类型的函数指针,如下所示:typedef void(* CallbackFn)(bool,std :: string,py :: array_t &); typedef std :: function

c++ c c++11 interop function-pointers
3个回答
6
投票

C不会/不能处理C ++名称修改(也不能处理与C类型不同的C ++类型)。您不能在暴露给C的任何东西中使用非POD类型(以及普通函数指针涉及在C中不可用的类型)。并且您需要对暴露的东西使用CallbackFn,以禁用名称修饰(或更确切地说,使用任何命名约定) /修改您当前使用的C编译器平台)。


4
投票

您可以通过声明extern "C"将函数公开给C。


0
投票

为了将任何C ++函数公开给C,您应该将C ++调用包装在纯C ++库中的C函数中。并仅从中导出C函数。对库内部和外部的C函数声明使用通用标头。这些函数可以在任何C环境中调用。所有C ++类型都包装在一个类中,并跨函数包装传递指向该类的指针,作为C ++环境的句柄。指向类的指针应为void *或仅长。而且只有在C ++方面,您才能将其重新解释为自己的环境类。更新1:

© www.soinside.com 2019 - 2024. All rights reserved.