Skip to content

Instantly share code, notes, and snippets.

@andreafioraldi
Last active October 5, 2020 09:46
Show Gist options
  • Save andreafioraldi/40d393b80635832da74a612e90596cbc to your computer and use it in GitHub Desktop.
Save andreafioraldi/40d393b80635832da74a612e90596cbc to your computer and use it in GitHub Desktop.
C to C++ and back
#include <stdio.h>
#include <stdlib.h>
#define offsetof(type, field) ((size_t)&(((type *)0)->field))
#define derived_cast(derived_type, obj) ((derived_type*)((char*)(obj) - offsetof(derived_type, base)))
/// BASE
struct base_C_class;
struct base_C_funcs {
void (*print)(struct base_C_class*);
};
struct base_C_class {
void* wrapper; // base classes need to have this field instead of the base field
struct base_C_funcs funcs;
int info;
};
void base_C_class_print(struct base_C_class* self) {
printf("base_C_class_print %d\n", self->info);
}
void base_C_class_init(struct base_C_class* self, int info) { // contructor
self->funcs.print = &base_C_class_print;
self->info = info;
}
struct base_C_class* create_base_C_object(int info) {
struct base_C_class* o = (struct base_C_class*)malloc(sizeof(struct base_C_class));
base_C_class_init(o, info);
return o;
}
/// DERIVED : BASE
struct derived_C_class;
struct drived_C_funcs {
void (*change_info)(struct derived_C_class*, int);
};
struct derived_C_class {
struct base_C_class base; // derived classes need to have this field instead of the wrapper field
struct base_C_class* objptr;
struct drived_C_funcs funcs;
};
void derived_C_class_print(struct base_C_class* self) {
struct derived_C_class* d_self = derived_cast(struct derived_C_class, self);
printf("derived_C_class %d\n", d_self->base.info);
}
void derived_C_class_change_info(struct derived_C_class* self, int info) {
self->base.info = info;
}
void derived_C_class_init(struct derived_C_class* self, int info) { // contructor
base_C_class_init(&self->base, info);
self->base.funcs.print = &derived_C_class_print;
}
struct derived_C_class* create_derived_C_object(int info) {
struct derived_C_class* o = (struct derived_C_class*)malloc(sizeof(struct derived_C_class));
derived_C_class_init(o, info);
return o;
}
/// C++ BASE
class Base {
protected:
struct base_C_class* bind;
void register_binding();
Base(struct base_C_class* from_c) {
bind = from_c;
bind->wrapper = static_cast<void*>(this);
register_binding(); // just the base funcs
}
public:
static Base* from_c_instance(struct base_C_class* obj) {
if (obj->wrapper)
return (Base*)obj->wrapper;
return new Base(obj);
}
struct base_C_class* to_c_instance() { // back to C
return bind;
}
Base(int info) : Base(create_base_C_object(info)) {}
virtual void print() {
base_C_class_print(bind);
}
// define getters/setters of fields
int get_info() {
return bind->info;
}
int set_info(int info) {
bind->info = info;
}
};
void Base::register_binding() {
bind->funcs.print = [](struct base_C_class* self) -> void {
Base* obj = static_cast<Base*>(self->wrapper);
obj->print(); // rely on the C++ class vtable
};
}
/// C++ DERIVED
class Derived : public Base {
protected:
Derived(struct derived_C_class* from_c) : Base((struct base_C_class*)from_c) {
// just the derived funcs
struct derived_C_class* d_bind = (struct derived_C_class*)bind;
d_bind->funcs.change_info = [](struct derived_C_class* self, int info) -> void {
Derived* obj = static_cast<Derived*>(self->base.wrapper);
obj->change_info(info); // rely on the C++ class vtable
};
}
public:
static Derived* from_c_instance(struct derived_C_class* obj) {
if (obj->base.wrapper)
return (Derived*)obj->base.wrapper;
return new Derived(obj);
}
struct derived_C_class* to_c_instance() { // back to C
return (struct derived_C_class*)bind;
}
Derived(int info) : Derived(create_derived_C_object(info)) {}
virtual void print() {
derived_C_class_print(bind);
}
virtual void change_info(int info) {
derived_C_class_change_info((struct derived_C_class*)bind, info);
}
Base* get_objptr() {
return Base::from_c_instance(((struct derived_C_class*)bind)->objptr);
}
};
/// C++ ONLY DERIVED SECOND CLASS
class CppDerived : public Base {
const char* str;
public:
CppDerived(const char* name, int info) : Base(info), str(name) {} // here we call the right constructor
virtual void print() {
printf("hello %s from C++ %d\n", str, get_info());
}
};
int main() {
Derived d(666);
d.print();
struct base_C_class* dc = (struct base_C_class*)d.to_c_instance();
dc->funcs.print(dc);
Base * b = &d;
b->print();
CppDerived cpp("andrea", 123);
cpp.print();
struct base_C_class* cppc = cpp.to_c_instance();
cppc->funcs.print(cppc);
}
@andreafioraldi
Copy link
Author

Notes:

In C vtable, add a create_wrapper entry that is an hook registered by the wrapper. In C++, do something like from_c(cptr) in which from_c creates an instance of Derived and cast it or return wrapper if any.

create a vtable too for C++ drived only classes in which the create_wrapper thing just return wrapper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment