API C / C ++ puzzle

This is a fully rewritten version of an earlier question ; I think the first version did not indicate important details; this one provides the whole context.

I have the header of some C ++ API. The API declares several classes as follows:

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

those. no members, all functions are built-in and public, except for constructors. Constructors are private, so as far as I understand C ++, I cannot name them. To create these objects, I have to use auto_ptr for them:

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

The API also has a second set of such functions:

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

Call them the main functions , because these are the characters actually exported from the main application. Not C ++ classes.

The main functions have a C-connection (that is, declared as extern "C" ), but they are declared as taking and returning C ++ types (for example, they can take a link: Foo &foo ). Finally, the header contains an implementation of the built-in functions of the C ++ classes. All these functions do the same: they call the main functions. For example, the FooAutoPtr constructor looks like this:

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

From what I understand, the code gets some object that should be a pointer to Foo from the host application and modifies gizmo auto_ptr to point to this object. But it seems to the developer that this was a true pointer to Foo . And the call to Foo::Bar() is as follows:

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

This applies to all C ++ classes and methods. Clever, huh?

Now, can someone explain what all this means? :) This is not a real C ++ API, is it? For me, it is more like a thin C ++ shell on top of the C API. If so, can I override the core functions to lose the C ++ bit ? I understand how to write a C shell around C ++ (in fact, I already wrote it), but if possible, I would prefer to lose the shell and use functions directly. But how can I lose C ++ stuff?

For example, there may be a function with links:

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

Right now I am calling it from my C ++ shell as follows:

 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 would prefer it to be redesigned as follows:

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

UPDATE I found an interesting thing that confirms Neil's answer . This is code in Common Lisp that uses the same API. (Naturally, he should use part C.) And, from what I can (barely) read in the source, the author simply used pointers instead of links. Here is a piece of code that converts C ++ declarations to Lisp:

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

So this is :) Thanks, everyone!

+6
source share
2 answers

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

+4
source
 #define & * // convert references into pointers. 

Stop. Right. There. It was a joke, not an attempt to see how many downvotes could be accumulated in one answer.

But the approach of rewriting the header file to replace links with pointers should certainly work. Since these are C functions, there is no problem to worry about, and I have not yet seen a compiler that does not implement references as pointers. (Is there another way?)

+1
source

Source: https://habr.com/ru/post/906893/


All Articles