Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping a C++ object in extern "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 I want to wrap this in extern "C" so that I can call it from many 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 this portable? Is the type unsigned "unsigned long" large enough for an object pointer? Any other problems with this approach?

Thank in advance for any answers!

like image 941
Andreas W.P. Avatar asked May 27 '11 13:05

Andreas W.P.


People also ask

What is C wrapper?

The C Wrapper provides access to RPC-based components from C applications and enables users to develop both clients and server. This section introduces the various possibilities for RPC-based client applications written in C. Using the C Wrapper in Single-threaded Environments (UNIX, Windows)

Can you use extern C in C?

By declaring a function with extern "C" , it changes the linkage requirements so that the C++ compiler does not add the extra mangling information to the symbol. This pattern relies on the presence of the __cplusplus definition when using the C++ compiler. If you are using the C compiler, extern "C" is not used.

Do C++ features are allowed in extern C block?

Not any C-header can be made compatible with C++ by merely wrapping in extern "C".

Can I use C libraries in C++?

Yes - C++ can use C libraries.


2 Answers

Yeah. It's bad. Really bad. unsigned long- just no. Return a properly typed BankAccount*- the other languages will see it on the other end as a generic pointer (such as System.IntPtr) and there's no need to return an untyped pointer when the binary interface doesn't type pointers anyway.

extern "C" BankAccount* CreateBankAccount() {
    return new BankAccount;
}
extern "C" void deposit(BankAccount* account, double amount) {
    account->deposit(amount);
}
like image 95
Puppy Avatar answered Oct 17 '22 02:10

Puppy


That basically looks fine with one proviso. Trying to use an integer type to hold a pointer is not a great idea—much better to use void* since that, by definition, is the width of a pointer.


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

like image 9
David Heffernan Avatar answered Oct 17 '22 01:10

David Heffernan