Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I expose C++ function pointers in C?

I have two types of function pointers defined in my C++ that look like this:

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);
};

and I want to be able to expose them in C but I can't seem to find a way to do so. My first try was to cast these as void* and then recast them back to their actual type. but this seems like a bad idea. So I'm clueless as how to go about this conversion.
Also the solution that I need to come-up with should be doable using C++11 at the very least.

Update:

Thank you very much for your answers. However I need to add a bit more explanation as what I'm after. I know about extern "C" and in fact the C++ functions are exposed using this already in my DLL. However, the problem I had was to pass the function pointers back and forth between the C and C++.
One way was to define function pointers in a way that can be directly usable by C. That is I needed to change for example :

typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
typedef std::function<void(std::string)> LogFunction;

to its C compatible one :

typedef void(*CCallbackFn)(bool, char*, int, unsigned char, int length);
typedef void(*CLogFunction)(char* string, int length);

and use these instead. However, the disadvantage of doing this is that, the DLL is also used by C++ clients and this would be a hindrance to change everything C++ to be compatible by C, I'd lose the advantages of C++ by doing this.
Instead I though of coming up with a second way. The C++ stays the same, but for C linkage and interacting with other languages through C API, I do the conversion myself.
That is they use C style and then I convert this back to C++ in the implementation part. In order to further simplify this so I designed some defaults on C++ part as well. Meaning, suppose for the lack of a better example, the instance needs a callback function to log whatever happens. I define a callback function in case it was not given by the user and create two functions for C API specifically something roughly similar to this:

//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);  
 }

and the client could for example use the get_default_log_callback and use its return to set_log_call_back. Basically the idea here is to be able to use the C++ already defined assets. I was stuck at this conversion process, how to convert such callback pointers to a C compatible type ( like what I showed, it'd be really easy to just cast the pointer to void* for example and write a C wrapper that accepts void* and then recast it to the proper type.

I'd like to know about this scenario as well and whether this is a good practice or the otherwise a bad one.

Question two:

Also I'd like to know if it is possible to have a conversion from for example the CCallbackFn and CallbackFn?
Suppose I've got a function(my C function above e.g.) in a CCalbackFn form ,but I want to ultimately have it in CallbackFn form(change it and call the underlying C++ that accepts CallbackFn) ? is this possible ?

like image 385
Hossein Avatar asked Apr 08 '20 13:04

Hossein


People also ask

How to use pointers in C programming language?

In Assembly Language They Are called as (call "function's memory address").Now come back to C If function has a memory address then they can be manipulated by Pointers in C.So By the rules of C 1.First you need to declare a pointer to function 2.Pass the Address of the Desired function

What is the declaration of a function pointer in C?

Declaration of a function pointer in C for the function foo will be Here, pointer *foo_pointer is a function pointer and stores the memory address of a function foo that takes two arguments of type int and returns a value of data type float.

Which instruction defines the array of function pointers in C++?

We called the appropriate array element (Function pointer) with arguments, and we store the result generated by the appropriate function. The instruction int (*ope [4]) (int, int); defines the array of function pointers.

When to use a void pointer in C++?

Void pointers are used during function declarations. We use a void * return type permits to return any type. If we assume that our parameters do not change when passing to a function, we declare it as const.


2 Answers

C doesn't do / cannot handle C++ name mangling (nor C++ types that are not identical to C types). You cannot use non-POD types (and plain function pointers involving types not usable in C) in anything exposed to C. And you need to use extern "C" for the exposed stuff, to disable name mangling (or rather, use whatever naming convention/mangling your current platforms C compiler uses).

In short: use extern "C" for anything that must be callable from C and make sure anything exposed that way only uses types that you can write/use in C.

like image 170
Jesper Juhl Avatar answered Sep 29 '22 09:09

Jesper Juhl


You can expose a function to C by declaring it extern "C".

However, the function must only accept argument types that are valid in C.

From the look of the code above, you're going to have to express your callback in more C-like terms.

like image 28
Richard Hodges Avatar answered Sep 29 '22 09:09

Richard Hodges