Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C/C++ API puzzle

Tags:

c++

c

reference

This is an completely rewritten version of an earlier question; I think the first version omitted important details; this one provides all the context.

I have a header of some C++ API. The API declares a few classes like this:

class Foo
{
public:
    inline void Bar(void);
    /* more inlines */
private:
    inline Foo();
    /* maybe more inline constructors */
}

I.e. no members, all functions are inline and public, except constructors. Constructors are private, so, as far as I understand C++, I cannot really call them. To create these objects I'm supposed to use auto_ptrs to them:

class FooAutoPtr : public std::auto_ptr<Foo> 
{
public:
    inline FooAutoPtr();
    /* one for each Foo constructors */
}

The API also has a second set of functions like this:

void Foo_Bar(void *self);
Foo* Foo_Constructor();

Let's call them core functions, because these are the symbols actually exported from the host app. Not the C++ classes.

Core functions have C linkage (i.e. they declared as extern "C"), but they are declared as taking and returning C++ types (e.g. they can take a reference: Foo &foo). Finally the header contains the implementation of the inline functions of the C++ classes. All these functions do the same: they call the core functions. For example, the FooAutoPtr constructor is like this:

inline FooAutoPtr::FooAutoPtr()
{
   reset(Foo_Constructor());
}

From what I understand, the code receives some object that is supposed to be a pointer to Foo from the host app and changes the auto_ptr gizmo to point to this object. But to the developer it looks as if it was a true pointer to Foo. And calling Foo::Bar() goes like this:

inline Foo::Bar()
{
    Foo_Bar(this);
}

This goes for all C++ classes and methods. Clever, huh?

Now, could somebody please explain what does all this mean? :) It's not a true C++ API, is it? To me it looks more like a thin C++ wrapper on top of a C API. If so, can I redeclare the core functions to lose the C++ bits? I understand how to write a C wrapper around C++ (actually, I already wrote it), but, if possible, I'd rather lose the wrapper and use the functions directly. But how do I lose the C++ stuff?

For example, there could be a function with references:

Bar& Foo_GetBar(void* self, const Baz& baz, int& i);

Right now I call it from my C++ wrapper like this:

typedef struct bar bar_t; /* and others */
/*...*/
bar_t*
foo_get_bar(foo_t* foo, baz_t* baz, int* i)
{
    return (bar_t*) &Foo_GetBar(foo, *(Baz*)baz, *i);
}

and it works (I have no idea, how). But I'd rather have it redeclared like this:

/* type? */ Foo_GetBar(foo_t*, /* type? /*, /* type? */);

UPDATE: I found an interesting thing that confirms Neil's answer. It is code in Common Lisp that uses the same API. (Naturally, it has to use the C part.) And, from what I can (barely) read in the source, the author simply used pointers in place of of references. Here's a snippet from code that converts C++ declarations into Lisp:

;; use * instead of & - we're not interested in C++ details
line (regex-replace-all "&" line "*")

So that's it :) Thanks, everyone!

like image 614
Mikhail Edoshin Avatar asked Jan 25 '12 20:01

Mikhail Edoshin


2 Answers

In theory, the details of how a compiler treats a reference in an C-linkage declaration is an unspecified implementation detail. However many compilers treat it as if it was a pointer. So if the C++ library header imports Bar& Foo_GetBar(void* self, const Baz& baz, int& i); then you could try importing it into your C header as bar_t* Foo_GetBar(foo_t* self, const baz_t* baz, int* i); and it might just work.

like image 79
Neil Avatar answered Nov 05 '22 13:11

Neil


#define & *    // convert references into pointers.

Stop. Right. There. That was a joke, rather than an attempt to see how many downvotes could be accumulated on a single answer.

But the approach of rewriting the header file to replace references with pointers should certainly work. Because these are C functions, there's no name mangling to worry about, and I've yet to see a compiler that doesn't implement references as pointers. (Is there any other possible way?)

like image 24
Roddy Avatar answered Nov 05 '22 12:11

Roddy