-2

I'd like to create a C wrapper for a C++ library I wrote.

All the examples and SO's answers I found:

Using void, typedef void myhdl_t

Trojan horse structure: struct mather{ void *obj; };

# .h
struct mather;
typedef struct mather mather_t;

# .cpp
struct mather{
    void *obj;
};

mather_t *mather_create(int start){
    mather_t *m;
    CPPMather *obj;

    m      = (typeof(m))malloc(sizeof(*m));
    obj    = new CPPMather(start);
    m->obj = obj;

    return m;
}

Deriving a struct from a C++ base class

# .h
struct Foo;

#.cpp
struct Foo : public FooInternal {
    using FooInternal::FooInternal;
};

struct Foo* foo_new() {
    try {
        return new Foo;
    } catch(...) {
        return nullptr;
    }
}

My case:

I'd like to have an allocation C function like that:

int alloc_function(struct Foo** foo){
  if (foo==nullptr)
    return -EFAULT; // The user gives nullptr
  if (*foo!=nullptr)
    return -EFAULT; // already allocated
  
  // error: Incompatible pointer types assigning to 'struct Foo *' from 'Foo *'
  *foo = new Foo;

  // No error but Clang-Tidy: Do not use static_cast to downcast from a base to a derived class
  *foo = static_cast<struct Foo*>(new Foo);

  return 0;
}

I understand Clang-Tidy isn't a compiler error but I still would like to do it the right way.

  • What's the best practice for writing a C-wrapper? Any real example?
Alexis
  • 2,136
  • 2
  • 19
  • 47
  • `error: Incompatible pointer types assigning to 'struct Foo *' from 'Foo *'` Post a full [MCVE]. `static_cast(new Foo);` just `reinterpret_cast` it. – KamilCuk Dec 01 '21 at 08:35

1 Answers1

1

My case:

I'd like to have an allocation C function like that:

int alloc_function(struct Foo** foo){

Foo is already a C++ type. Use a different one. Use a void * pointer.

struct CFoo {
   void *pnt;
};

extern "C"
int alloc_function(struct CFoo* foo) {
  if (!foo)
     return -EINVAL; // That is no EFAULT, it's EINVAL.
  try { 
     foo->pnt = reinterpret_cast<void*>(new Foo);
  } ...
  return 0;

}

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 2
    Rather than wrapping the `new Foo` in a `try`/`catch`, better to use `new (std::nothrow) Foo`. Instead of throwing on failure, it gives a null pointer. – Peter Dec 01 '21 at 09:02
  • @KamilCuk Thank you, is the trojan structure the best way/practice? How about "My case" with derived struct from the class? And why is it better than using `typedef void foo_t`? – Alexis Dec 01 '21 at 09:35
  • @Peter I didn't know about it, thanks for the best practice! – Alexis Dec 01 '21 at 09:37
  • 1
    `is the trojan structure the best way/practice?` Is subjective and strongly depends on specific case. `How about "My case" with derived struct from the class?` How about it? Make sure to call destructor with proper type. `why is it better than using typedef void foo_t?` To allow static type checking from the compiler on C side. `better to use new (std::nothrow) Foo. Instead of throwing on failure` While this is true, `Foo` constructor can also throw - and we don't want to leak exceptions. – KamilCuk Dec 01 '21 at 09:40