Monday, September 8, 2008

Calling C++ Functions in C

<skippable>
I'm currently working on some code written in C, I've never done C programming before; only Java and a little bit of Python. I'm currently in the process of learning C, so whatever I write may not be the best way to do "that" thing. But as I keep learning new things, I'll blog them when I find time. So if you're interested in learning C, follow my posts; especially if you're a Java programmer who doesn't know C but you're interested just for the heck of it. You may find these posts useful.
</skippable>

I'd to call a few C++ class's methods from a C program recently, and I didn't know how to do it. I found a way that suits my situation and here it is.

The fact as I found out is that you cannot create an instance of a C++ object in your C program and obviously that means you can't call its methods. So, we need a workaround. In general, we need to be able to do these things from our C code:
  1. Create an instance of a C++ class
  2. Call its methods, pass arguments, etc.
  3. Destroy the created instance.
(Instance == Object). Just thought I should let you know!
I'll demonstrate the process with an example. So up first, let's create a C++ class which we'll call from a C program.

// cppclass.cpp
class CppClass
{
public:
    char *returnHello()
    {
        char *ret_val = "Hello";
        return ret_val;
    }
};

But I've already told you that we can't create an instance of this class directly, so we've to provide wrapper functions that our C program can call. The disadvantage with this workaround is, for every public function we want to use we need a wrapper function. Anyway, let's write them.

(Add the following lines to cppclass.cpp file)

extern "C" void *create_cppclass()
{
    return new CppClass();
}

extern "C" char *call_return_hello(void *obj)
{
    return reinterpret_cast<CppClass*>(obj)->returnHello();
}

extern "C" void *free_cppclass(void *obj)
{
    delete reinterpret_cast<CppClass*>(obj);
}


A few things should be noticed here.

  • All these wrapper functions are preceded with extern "C" (uppercase C)
  • In create_cppclass() wrapper function, the newly created object of CppClass is returned as a void pointer (void *). Void pointers can be used to point to any type. So when we return the instance as a pointer to void in this function, it can stored it in our C program. That's the whole point here.
  • In call_return_hello() and free_cppclass() wrapper functions, we use reinterpret_cast to convert the void pointer back to CppClass pointer type. The -> operator is used for dereferencing the pointers instead of the . (dot) operator.
Now, let's call these functions from our C program. We should declare these functions first in our C program before we can use them.

// cfile.c
#include <stdio.h>

extern "C" void *create_cppclass();
extern "C" char *call_return_hello(void *obj);
extern "C" void *free_cppclass(void *obj);

main()
{
    void *obj = create_cppclass();
    char *hello = call_return_hello(obj);
    free_cppclass(obj);
    printf("%s\n", hello);
}

Now, I'll use g++ to compile:

g++ -o go cfile.c cppclass.cpp
./go

-o indicates the executable output file name which is "go" here. Write the code and try out for yourself. It should print "Hello" (Duh!)

That's it.