I am working on wrapping a C++ library in C. The C++ library is a library for a database server. It uses a wrapper class for passing around serialized data. I can't use that class directly in C, so I defined a struct that can be used in C code like this:
In include/c-wrapper/c-wrapper.h (this is the wrapper that clients of my C wrapper are including)
extern "C" {
typedef struct Hazelcast_Data_t Hazelcast_Data_t;
Hazelcast_Data_t *stringToData(char *str);
void freeData(Hazelcast_Data_t *d);
}
In impl.pp
extern "C" struct Hazelcast_Data_t {
hazelcast::client::serialization::pimpl::Data data; // this is the C++ class
};
Hazelcast_Data_t *stringToData(char *str) {
Data d = serializer.serialize(str);
Hazelcast_Data_t *dataStruct = new Hazelcast_Data_t();
dataStruct->data = d;
return dataStruct;
}
...
Now this works, the client of my C library only sees typedef struct Hazelcast_Data_t Hazelcast_Data_t;. The problem is, that the aforementioned type cannot be allocated on the stack, like if I would like to provide an API like this:
// this is what I want to achieve, but Hazelcast_Data_t is an incomplete type
#include <include/c-wrapper/c-wrapper.h>
int main() {
char *str = "BLA";
Hazelcast_Data_t d;
stringToData(str, &d);
}
The compiler will throw an error that Hazelcast_Data_t is an incomplete type. I would still like to provide an API that allows to pass a stack-allocated reference of Hazelcast_Data_t to the serialization function, but because Hazelcast_Data_t has a pointer to the C++ class, this seems pretty much impossible. Having the option to pass a stack allocated reference however would greatly simplify the code for the client of my C library (no need to free the newed structure).
Is it somehow doable to redefine Hazelcast_Data_t type so that it can be used in C and still be allocated on the stack?
Most of the hacks you're thinking of for doing this invoke undefined behaviour, since C will not call the C++ constructor for the contained object when the struct is created, and not call the C++ destructor when the struct goes out of scope. To make it work you need the struct to contain a buffer of the right size and new into that buffer in an init function, and call the destructor on that buffer when done. This means the code looks like this (assuming that nothing throws - in which case you need to add exception handling and translation...)
struct wrapper {
char buffer[SIZE_OF_CXX_CLASS];
}
void wrapper_init() {
new (buffer) Wrapped();
}
void wrapper_destroy() {
((Wrapper*)buffer)->~Wrapper();
}
{
struct wrapper wrapped;
wrapper_init(&wrapped);
// ... use it ...
wrapper_destroy(&wrapped);
}
If you forget to call wrapper_init everything goes into undefined behvaiour land. If you forget to call wrapper_destroy I think you get UB too.
But since this forces your caller to call the init and destroy functions there's very little gain over using a pointer. I'd go so far as to claim that the use of a struct rather than a pointer suggests to API users that initialisation should be trivial, and destruction unnecessary. I.e. as an API user I'd expect to be able to do
{
struct wrapper wrapped = WRAPPER_INIT; //Trivial initialisaton macro
// .. use it ..
// No need to do anything it is a trivial object.
}
In the cases where this is not possible (like yours) I'd stick with the usual allocate it on the heap idiom
{
struct wrapper* wrapped = wrapper_create();
// ... use it ...
wrapper_destroy(wrapped);
}
You need to provide a definition of the struct in your header file such so that clients know how much space to allocate on the stack. But that becomes tricky when the underlying representation in a C++ class which can't be exposed by the extern "C".
The solution is a pointer to the C++ class rather than the actual class. As pointers are the same size this will work in the C client, even when it has no knowledge of C++.
Thus in the header
typedef struct Hazelcast_Data_t {
void *data
} Hazelcast_Data_t
And in the C++ file you can use static_cast to access the C++ class via this pointer.
Make a wrapper struct that simply contains an array large and aligned enough to contain your C++ type. Placement-new your C++ type in it.
You will probably have to build a small C++ executable that would generate a C header file with SIZEOF_HAZELCAST_T and ALIGNOF_HAZELCAST_T appropriately defined.
Related
I have a class, Component, which has to interact with C code.
//// Component.h file ////
class Component{
public:
uint8_t getdevice1Value();
void setdevice1Value(uint8_t value);
uint8_t getdevice2Value();
void setdevice2Value(uint8_t uint8_t);
private:
uint8_t device1Value;
uint8_t device2Value;
}
The object of the class would be created when its relevant thread is created in some Application.cpp file:
///////Some function where the Component is used//////
createThread(){
Component myComponent; // Scope within the thread
// Some actions
}
Now comes my C code, which happens to be event driven. Within these functions, I would like to link my Class methods:
//// device1_event.c file ////
void command_get_device_value()
{
// code
// assign variable = Component::getdevice1Value() function
// code
}
void command_set_device_value()
{
// code
// call Component::setdevice1Value(variable) passing some variable
// code
}
Similar to device1_event.c file, I have another device2_event.c where I would like to map the function calls to getdevice2Value and setdevice2Value.
I looked at the questions Using a C++ class member function (cannot be static) as a C callback function or also this Pass a C++ member function to a C function, where a struct registers the context and the function pointers.
I have a constraint in my case of not being able to dynamic allocation. So, I cannot use the new operator.
Now I have a few questions regarding these:
Is the callback concept applicable in my case?
If the first question is a yes, then:
How do I go about implementing it. I am a bit confused about this. I mean the call-functions need to be placed within the C-functions and also I need to register them once the Component instance is created. How can I exactly do this?
How do I bring the callback functions to my C files?
In this question a struct was employed. Where do I declare the 'struct'? I did try declaring it in the Component.h file and introduced it as an extern within the device1_event.c file. But I get an incomplete type error.
The classical C way of passing callbacks is to pass two values: a pointer to the callback itself, and an opaque pointer which will be passed to the callback as an additional argument (take a look at qsort_r for example). When interfacing with C++, that opaque value may be used as instance pointer; you will only need to write a thin wrapper:
class B {
void my_callback(int arg);
static void my_callback_wrapper(int arg, void *u) {
((B*)u)->my_callback(arg);
}
};
// or even:
extern "C" void my_callback_wrapper(int arg, void *u) {
((B*)u)->my_callback(arg);
}
and pass a pointer to the wrapper, along with a pointer to the object, to the C part. Be careful to use the exact same class type on both sides and not base/derived classes, for example.
Note that while it may be possible to get a pointer to the (non-static) method itself, on some compilers (tested on MSVC a long time ago) they have a special calling convention so that the pointer will not be compatible with any normal function pointer.
There are dozens upon dozens of SO questions and blog posts that describe wrapping a C++ class with a C API. Example Wrapping C++ class API for C consumption
Most of these answers and blogposts go for something like this:
typedef void* CMyClass;
But others say that this is bad because it provides no type safety. They propose various variations of opaque structs, without any explanation. I could just copy the above snippet and move on with my life (which I will do in the meantime), but I'd like to know once and for all
Which form is the best?
Which guarantees does it provide over void*?
How does it work?
Use struct MyType in C++.
Use typedef struct MyType* pMyType; as your common handle.
Your "C" APIs should compile in both C and C++ (with extern "C" wrappers in C++ to get correct linkage). And you'll get close to max type safety.
Now, struct MyHandle{void* private_ptr;}; is another option: this avoids exposing the name of the C++ type to C. And so long as you isolate direct interaction with private_ptr to a handful of functions, it will be as type safe everywhere else.
The problem with void * is that it gives you no protection from accidentally assigning an incompatible pointer.
typedef void *CMyClass;
int i = 1;
CMyClass c = &i; // No complaints
If you instead typedef to some unique opaque type the compiler will help you.
typedef struct MyClass *CMyClass;
int i = 1;
CMyClass c = &i; // BOOM!
I think in C this is not an error but Clang 6.0 warns me with (even without any warnings enabled)
warning: incompatible pointer types initializing 'CMyClass' (aka 'struct MyClass *') with an expression of type 'int *'
The first thing is that void * is indeed not a good choice because it makes API more error prone by silently accepting any unrelated pointers. So the better idea would be to add a forward declaration to some struct and accept a pointer to that struct:
#ifdef __cplusplus
extern "C"
{
#endif
struct CMyClassTag;
typedef struct CMyClassTag CMyClass;
void CMyClass_Work(CMyClass * p_self);
#ifdef __cplusplus
}
#endif
The next step is to explicitly tell user that this pointer is opaque and is not supposed to be dereferenced by hiding pointer as unnecessary implementation detail:
typedef struct CMyClassTag * CMyClassHandle;
void CMyClass_Work(CMyClassHandle h_my_class);
Additionally rather that relying on user to correctly utilize this interface you can make real handle type rather than an opaque pointer. This could be done in several ways, but the main idea is to pass some obscure integer identifier and perform mapping from it to real pointer on library side at runtime:
typedef uintptr_t CMyClassHandle;
void CMyClass_Work(CMyClassHandle h_my_class);
// impl
void CMyClass_Work(CMyClassHandle h_my_class)
{
auto it{s_instances_map.find(h_my_class)};
if(s_instances_map.end() != it)
{
auto & self{it->second};
// ...
}
}
I know that flexible array member is not part of the C++11 standard.
So what is the correct way of interoperating with C code that return, or accept as argument, structs with flexible array member, from C++11?
Should I write a shim that maps the flexible array member from the C struct to a pointer in C++?
As far as I am aware, standard C++ won't even accept the declaration of a struct with a flexible array member. With that being the case, I see no alternative but to write wrapper functions (in C), unless the structure type containing the FAM can be opaque to your C++ code. I'm uncertain whether a wrapper is the kind of shim you had in mind.
Before we go further, however, I should point out that the problem is substantially different if your C functions accept and return pointers to structures with a flexible array member than if they pass and return the actual structures. I'll assume that they do work with pointers to these structures, for otherwise there seems no point to having the FAM in the first place.
I guess that given a C declaration such as
struct foo {
int count;
my_type fam[];
};
I would represent the same data in C++ as
struct cpp_foo {
int count;
my_type *fam;
};
, which of course can be handled by C, as well. Be aware that you cannot successfully cast between these, because arrays are not pointers.
Given a C function
struct foo *do_something(struct foo *input);
the needed wrapper might then look like this:
struct cpp_foo *do_something_wrap(struct cpp_foo *input) {
struct cpp_foo *cpp_output = NULL;
// Prepare the input structure
size_t fam_size = input->count * sizeof(*input->fam);
struct foo *temp = malloc(sizeof(*temp) + fam_size);
if (!temp) {
// handle allocation error ...
} else {
struct foo *output;
temp->count = input->count;
memcpy(temp->fam, input->fam, fam_size);
// call the function
output = do_something(temp);
if (output) {
// Create a copy of the output in C++ flavor
cpp_output = malloc(sizeof(*cpp_output));
if (!cpp_output) {
// handle allocation error
} else {
fam_size = output->count * sizeof(output->fam[0])
cpp_output->fam = malloc(fam_size);
if (!cpp_output) // handle allocation error
memcpy(cpp_output->fam, output->fam, fam_size);
// Supposing that we are responsible for the output object ...
free(output);
}
} // else cpp_output is already NULL
free(temp);
}
return cpp_output;
}
Naturally, if you have several functions to wrap then you probably want to write reusable conversion functions to simplify it.
There's a trick used by Windows by setting the flexible array member to have size 1 (because the Win32 API has been developed long before the feature ever went into C99, let alone C++)
struct foo {
int count;
my_type fam[1];
};
If you're allowed to change the C version then use the same struct in both C and C++. In case you can't change the C version then you'll need to redefine the struct in C++. You still have to change the C++ code when the C struct was modified, but at least it'll compile fine
See also
Are flexible array members valid in C++?
Why do some structures end with an array of size 1?
As flexible array members cannot to exposed to C++ (my_type fam[]; is not a valid C++ member), we'll have to define your own type.
Luckily C linkage functions don't have symbols that depend on their arguments. So we can either modify the definition of foo within shared headers, or define our own and don't include their headers.
This is a struct that is likely to be compatible layout-wise. Note that you should never declare these on the stack in C++:
struct foo {
int count;
#ifndef __cplusplus
my_type fam[];
#else
my_type do_not_use_fam_placeholder;
my_type* fam() {
return &do_not_use_fam_placeholder;
}
my_type const* fam() const {
return &do_not_use_fam_placeholder;
}
#endif
};
This relies upon the binary layout of the foo structure in C to be the prefix members, followed by the flexible array member's elements, and no additional packing or alignment be done. It also requires that the flexible array member never be empty.
I would use this+1 but that runs into alignment issues if there is padding between count and fam.
Use of memcpy or memmov or the like on foo is not advised. In general, creating a foo on the C++ side isn't a good idea. If you have to, you could do something like this:
struct foo_header {
int count;
};
foo* create_foo_in_cpp(int count) {
std::size_t bytes = sizeof(foo)+sizeof(my_type)*(count-1);
foo* r = (foo*)malloc(bytes);
::new((void*)r) foo_header{count};
for (int i = 0; i < count; ++i)
::new( (void*)(r->fam()+i) my_type();
return r;
};
which constructs every object in question in C++. C++'s object existence rules are more strict than C's; merely taking some POD memory and interpreting it as a POD is not a valid action in C++, while it is in C. The news above will be optimized to noops at runtime, but are required by C++ to declare that the memory in question should be treated as objects of that type under strict reading of the standard.
Now, there are some standard issues (defects) with manually per-element constructing the elements of an array, and layout-compatibility between arrays and elements, so you'll have to trust somewhat that the ABI of the C++ compiler and the C code is compatible (or check it).
In general, all interop between C and C++ is undefined by the C++ standard (other than some parts of the standard C library which C++ incorporates; even here, there is no mandate that C++ use the same C library). You must understand how your particular implementation of C and C++ interoprate.
So I've read Developing C wrapper API for Object-Oriented C++ code and I like the approach, which I have taken with my library - opaque handles for each corresponding C++ class; avoiding using void*
But now, I'm faced with thinking about 'interfaces', and base classes. For example, I have a class hierarchy of "channel" classes - a base class for a "channel" and derived concrete classes for, for example, serial comms, in-memory buffers, sockets, etc.
So I have:
typedef struct serial_channel serial_channel;
typedef struct socket_channel socket_channel;
typedef struct memory_channel memory_channel;
serial_channel* create_serial_channel();
socket_channel* create_socket_channel();
memory_channel* create_memory_channel();
But I want to be able to pass any one of those into a function to associate it with a 'device' object:
void associate_device_with_channel(device*, channel*);
Easy in C++, since it understands base classes. How do I approach this in the C wrapper library - what type is channel in C?
The only thing I can think of is that I must resort to void* to represent a base class?
typedef void* channel;
void associate_device_with_channel(device*, channel*);
It works, but would let me pass any pointer?
On the other extreme, I can write a set of functions matching the derived channel classes:
void associate_device_with_serial_channel(device*, serial_channel*);
void associate_device_with_socket_channel(device*, socket_channel*);
void associate_device_with_memory_channel(device*, memory_channel*);
It's very verbose, and if I have to add new channel types, I have to add new functions to the interface as well.
Is there some kind of middle ground I've been missing? - like a single function, but not void*?
There isn't any perfect approach. You're trying to make your function take some opaque handles (the ones with the appropriate base class) but not any handle type (which void* would accept), and there just isn't a thing in C for that.
If you like, you can provide a function which takes serial_channel* and returns channel*, and another one for each other channel subclass. This gets you away from unsafe C casting, and doesn't require numfuncs*numderivedclasses different channel-taking functions.
Personally, I'd just void* it. They're using C, after all... clearly they don't care too much about their language keeping them safe.
First, I would set up my structures something like this:
typedef void base_class;
struct base_class_impl
{
// base class member variables go here
}
struct derived_class
{
// base class must come first in the derived struct
struct base_class_impl base;
// derived class member variables go here
}
Then, I would take pointers to base_class as arguments to my functions:
int base_class_get_count(base_class *b);
and I would always cast at the start of the function:
int base_class_get_count(base_class *b)
{
struct base_class *base = (struct base_class *)b;
// Operate on the object now
}
This enables base_class_get_count() to work even on objects of the derived type. The downside is that it doesn't allow the derived type to override a method - you would have to go a step further, implementing your own table of function pointers which the API calls (like base_class_get_count) dispatch out to, based on the entry in the table.
If you only target GCC or Clang (I suspect that you wouldn't bother with C if you were targeting Visual Studio), one of your options is to create a union with the non-standard __transparent_union__ attribute to list the types that a function can accept. A function accepting a union parameter with the __transparent_union__ attribute will accept either that union, or any type contained in it.
union associable_channel
{
channel* a;
serial_channel* b;
socket_channel* c;
memory_channel* d;
} __attribute__((__transparent_union__));
void associate_device_with_channel(union associable_channel chan);
serial_channel* serial;
socket_channel* socket;
memory_channel* mem;
associate_device_with_channel(serial);
associate_device_with_channel(socket);
associate_device_with_channel(mem);
gcc 4.4.4 c89
I was just reading a discussion at DevX about calling C++ code from C since I have to do something similar. I am just wondering what user Vijayan meant by "make sure that non POD types in C++ are opaque to C clients."
Many thanks for any suggestions,
C can only deal with POD types.
Consequently, you cannot pass objects of non-POD types to C programs (by value). Also, if you pass pointers of non-POD types to C programs, they can't interact with the objects pointed to.
POD = Plain old data structure = C structs, no virtual methods, etc. You need to write wrapper functions for C to access non-POD types (i.e., classes).
More on POD:
http://en.wikipedia.org/wiki/Plain_old_data_structure
For a type to be opaque means you can't look inside it: it's a "black box" that can be passed around but not inspected or manipulated directly by the C code. You typically refer to the object using either heap-allocated memory and void*s, or using functions to determine the necessary length and buffers.
For example, a C++ object might contain a std::string, but the layout of a std::string is not specified in the C++ Standard, so you can't write C code that directly reads from or writes to the string (at least, not without having a total understanding of the std::string layout, manually revalidated every time the compiler/STL is updated).
So, to allow C code to access the object, you might write C-callable functions such as:
#if __cplusplus
extern "C" {
#endif
void* object_new();
const char* object_get_string(void* p_object);
void object_set_string(void* p_object, const char* s);
void object_delete();
#if _cplusplus
}
#endif
With C++ implementation ala:
class Object { std::string string_; ... }
void* object_new() { return new Object; }
const char* object_get_string(void* p) { return ((Object*)p)->string_.c_str()); }
...
Here, the object_XXX functions provide the C code with a safe way to use the Object.
Making the type opaque means, as per the line in the link:
typedef struct base base ; /* opaque */
makes the name of the handle available to C code, but not the definition of the type. This means that the C code cannot access any members directly, but has to go through the interface functions.
Note that you do not have to make a cast to a generic , i.e. void*, pointer, although doing so is one option, as per 9dan's answer.
Note that such a style of interface is in my experience a very nice way to manage encapsulation even in pure C code, just as in the standard C streams library.
Making opaque to clients means nothing special. C stream file I/O (FILE* f = fopen) API is the typical example that present opaque handle to clients.
Apparently C can not handle non-POD type so you must hide C++ implementation from C clients but provide access method.
Example:
C++ Implementation
class MyLibrary {
MyLibrary();
~MyLibrary();
int DoSomething();
...
}
Declaration for C clients
typedef void* OPAQUEHANDLE;
extern OPAQUEHANDLE MyLibrary_OpenLibrary();
extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h);
extern int MyLibrary_DoSometing(OPAQUEHANDLE h);
Implementation for C clients (in .cpp file)
extern OPAQUEHANDLE MyLibrary_OpenLibrary()
{
return new MyLibrary;
}
extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h)
{
delete (MyLibrary*) h;
}
extern int MyLibrary_DoSometing(OPAQUEHANDLE h)
{
return ((MyLibrary*)h)->DoSomething();
}