Wrapping a C ++ Object in External "C"

consider a simple example class:

class BankAccount { public: BankAccount() { balance =0.0; }; ~BankAccount() {}; void deposit(double amount) { balance += amount; } private: double balance; }; 

Now say that I want to wrap this in extern "C" so that I can call it from different programming languages ​​such as C # and Java. I tried the following, which seemed to work:

 // cbankAccount.h: extern "C" unsigned long createBackAccount(); extern "C" void deposit(unsigned long bankAccount, double amount); // cbankAccount.cpp unsigned long createBackAccount() { BankAccount *b = new BankAccount(); return (unsigned long) b; } void deposit(unsigned long bankAccount, double amount) { BankAccount *b = (BankAccount*) bankAccount; b->deposit(amount); } 

Is it portable? Is the type unsigned long unsigned long large enough for an object pointer? Any other problems with this approach?

Thanks in advance for any answers!

+7
source share
6 answers

Yes. This is bad. Really bad. unsigned long - just not. Return a correctly typed BankAccount* - other languages ​​will see it at the other end as a common pointer (for example, System.IntPtr), and there is no need to return an untyped pointer when the binary interface does not enter pointers in any case.

 extern "C" BankAccount* CreateBankAccount() { return new BankAccount; } extern "C" void deposit(BankAccount* account, double amount) { account->deposit(amount); } 
+10
source

It basically looks good with one caveat. Trying to use an integer type to hold a pointer is not a good idea - it is much better to use void* , because by definition it is the width of the pointer.


In fact, I think @DeadMG's answer is a cleaner approach than this.

+9
source

Type-strong is even better than void *.

 typedef struct BankAccountProxy * BankAccountPtr; BankAccountPtr createBackAccount() { BankAccount *b = new BankAccount(); return (BankAccountPtr) b; } 
+5
source

This is not portable because an unsigned long may not be long enough for a pointer. Not such a rare platform where this happens, it is win64.

Better to use ptrdiff_t or void* .

+3
source

It probably depends on the platform whether the long enough big (probably not on x86-64) alternative is to use something like swig

+3
source

I use void * instead of unsigned long.

+2
source

All Articles