Using A C++ Library From C

Posted: January 16, 2012


Here's an example of how to make calls into a C++ library from a straight C program. To me this is a neat demonstration because it shows how a C++ program is kind of "flattened" into a straight C program before it is put into the ELF library.

The C++ Library

#include <stdio.h> #include <stdlib.h> class testing { public: testing(); void print_a(); void print_b(); void print_both(); int a; int b; }; testing::testing() { a = 5; b = 6; } void testing::print_a() { printf("%d\n", a); } void testing::print_b() { printf("%d\n", b); } void testing::print_both() { printf("%d %d\n", a, b); }

The sample code above is compiled with the line: g++ -o cpplib.cxx -Wall -shared -fPIC

The C Program

#include <stdio.h> #include <stdlib.hgt; struct _testing { int a; int b; }; void _ZN7testingC1Ev(struct _testing *self); void _ZN7testing7print_aEv(struct _testing *self); void _ZN7testing7print_bEv(struct _testing *self); int main(int argc, char *argv[]) { struct _testing testing; _ZN7testingC1Ev(&testing); _ZN7testing7print_aEv(&testing); _ZN7testing7print_bEv(&testing); return 0; }

The above C program is compiled with: gcc -o callcpp callcpp.c -Wall -L. -lcpplib -lstdc++

So the first thing to note is I created a C structure that matches the C++ class without the functions. It's important to note that the C++ class did not contain any virtual functions. Had there been any virtual functions, a void *vtable; should be added to the top of the structure. I'm not sure if this applies to all C++ compilers or just to g++, but if a class has virtual functions a pointer to the vtable is the first entry in the struct. Also, all functions must be implented outside of the class { } area. Any functions defined and implemented in the class { } do not appear to be exported.

So the next step would be to figure out what functions are being exported by the library. A simple "objdump -t" dumps all the symbols exported in this library. The function names in C++ are "decorated" when being written to the ELF file. The decoration includes the class name the function comes from and information about the parameters being passed to it. For example _ZN7testing7print_aEv would tell us that the class testing has a function called "print_a" taking no paramters. All C++ functions have a hidden paramter that represents "this". So in the case above, print_a() for class testing is prototyped in C as: void _ZN7testing7print_aEv(struct _testing *self);. So that's pretty much all there is to know. In the above program an instance of struct _testing is allocated on the stack (no malloc() in this case). To finish constructing of the class/struct the constructor function for class testing is called manually from C with _ZN7testingC1Ev(&testing);. The next two lines simply test test print_a() and print_b() passing in the pointer to testing as "this". Technically I should have called the destructor for class testing, but to keep the code smaller I left it out since it doesn't do anything anyway.

Copyright 1997-2023 - Michael Kohn