Wrapping C++ exceptions, templated and classes in C

Sometime some libraries is distributed only as C++ libs or in template code. Or plug-ins for some programs is only in C or other language.

Here can join C and C++ compiled code and there will no big difference with language you use. Only need to choose right compiler for compilation. C++ stuff can be easily hidden and you can use some C++ "only" features in C without notice it.

Use templates from C.

Templates is most C++'sh part of all. Templates are defined in C++ headers and there not generate code. Only when you use they generate code. It reason why cannot include them inside *.so or *.a libraries. But you can always generated templates function examples that will generate code. And it means it now can be inside *.so and *.a. To use templates from C and compile it with C we need to hide C++ headers from C and create templates generated code

C compatible header code.h

1
2
extern float cmpx_add_f(float, float);
extern int   cmpx_add_i( int, int );

C++ template code.hpp

1
2
3
4
5
template <typename T>
inline T cmpx_add( T a, T b )
{
    return a+b;
}

Tell C++ to generate code for specific templates code.hpp

1
2
template int cmpx_add<int>(int, int);
template float cmpx_add<float>(float, float);

Write C compatible wrapper in C++

1
2
3
4
5
6
7
8
9
float cmpx_add_f( float a, float b )
{
    return cmpx_add<float>(a,b);
}
 
int cmpx_add_i( int a, int b )
{
    return cmpx_add<int>(a,b);
}

lets see now object file info

readelf -a
1
2
3
4
18: 0000000000000000 63 FUNC GLOBAL DEFAULT 5 cmpx_add_f
20: 0000000000000000 42 FUNC WEAK DEFAULT 13 _Z8cmpx_addIfET_S0_S0_
21: 000000000000003f 31 FUNC GLOBAL DEFAULT 5 cmpx_add_i
22: 0000000000000000 20 FUNC WEAK DEFAULT 12 _Z8cmpx_addIiET_S0_S0_

We see that functions inside code.h is globally visible and we can use them without problem from C.

Use C++ exceptions

Exceptions is usually very C++'sh everyone know that exceptions cannot be used in C. There is some C libraries that add some kind exceptions for C. That libraries usually uses setjmp and longjmp for simulating that kind of stuff.

C header

1
extern void  raise_exception( int );

C++ code for raising exceptions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
extern void raise_exception( int a )
{
    try
    {
        int b;
        b = b/a;
        printf("Everything ok ;]\n");
    }
    catch ( int e )
    {
        printf("Catching up exception number %d \n",e);
    }
}

C use exceptions

1
2
raise_exception( 1 );
raise_exception( 0 );

Here is seen that C++ exception raises inside C code. There can be made some code additions and C++ exceptions can be used in C with some tricks. Not yet proof of concept. But with pointers to functions (wasn't they called callbacks?) it cone be done.

Use C++ classes

C completable headers

1
2
3
4
extern void* clA_init();
extern void  clA_add( void*,int, int );
extern int   clA_empty( void* );
extern void  clA_destroy( void* );

C++ class definitions

1
2
3
4
5
6
7
8
9
class A
{
    public:
        char *p;
        A();
        ~A();
        void add( int, int );
        bool empty();
};

C++ class implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
A::A()
{
    this->p = (char *)malloc(1024);
}
 
A::~A()
{
    printf("Free Class Baby!!!\n");
    if (this->p != NULL)
    {
        free( this->p);
    }
}
 
void A::add( int a, int b )
{
    int i = cmpx_add_i( a , b );
    printf("%d\n", i);
}
 
bool A::empty()
{
    if (this->p == NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

C++ wrapping functions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
extern void* clA_init()
{
    A *a = new A;
    return (void *)a;
}
 
 
extern void clA_add( void *c, int a, int b )
{
    A *cl=(A*)c;
    cl->add( a, b );
}
 
extern int clA_empty( void *c )
{
    A *cl=(A*)c;
    bool b = cl->empty();
    if ( b == true ) 
    {
        return 1;
    } else
    {
        return 0;
    }
}
 
extern void clA_destroy( void *c )
{
    A *cl = (A*)c;
    cl->~A();
}

It easy to give C++ class to C as void* and then use C++ class functions (wasnt they called methods?) from C simply as pointers. It segfault oriented but it the way how it works.

These examples shows that you can stay as much as possible with C and use C++ compiled code.

Links

http://linux.die.net/man/1/readelf
http://gcc.gnu.org/codingconventions.html#ExternC
http://www.cplusplus.com/doc/tutorial/classes/
http://linux.die.net/man/3/setjmp
http://linux.die.net/man/3/longjmp

Downloads

c_cpp_tricks.tar.gz - 2KiB - http://archive.main.lv/files/writeup/wrapping_c___exceptions,_templated_and_classes_in_c/c_cpp_tricks.tar.gz