Using A C++ Library From CPosted: January 16, 2012 Introduction 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 libcpplib.so 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 libcpplib.so" 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-2025 - Michael Kohn
|