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.

4 comments:

Anonymous said...

I wonder how easy it is to write scripts to generate the wrappers? Surely not too difficult, and certainly less hassle than manually writing wrappers for dozens of classes.

Srikanth said...

Yes Kensson, that is certainly a great idea if you have too many functions to wrap.

You can also write an adaptor and just wrap those functions that you'd like to use in your C program if you aren't going to wrap a lot of functions.

Anonymous said...

Srikanth, nice info, nice blog.

Srikanth said...

Thanks for the kind words, Jadu.

Post a Comment