Using C Libraries for C++ Programs

Using C Libraries for C++ Programs

Yes, C++ can compile C with a C++ compiler and you can link C++ against C. Just be sure that any C function you call uses C linkage. This is made by enclosing the prototype of the C function by an extern "C"

#ifdef __cplusplus
extern "C"{
#endif

void c_function_prototype();

#ifdef __cplusplus
}
#endif

The headers for the library you are trying to use may already do that.

Is it possible to include C++ libraries in C programs?

No, it is not possible. One thing that is certanly going to miss are exception handling functions. You have to compile the main using c++ compiler.

If you really want to develop in c, and use a c++ library, you can develop a c library, and compile main with g++.


Even if compiling succeeds, linking will fail at the end. See :
Why can't I link a mixed C/C++ static library that has a C interface using gcc?

And it is not only exception functionality missing. There are lots of other things, which can be easily solved by using g++ to link everything.

As I said above, the solution is to call some function from main and link it with g++ :

#include "my_c_main.h"

int main(int argc, char* argv[])
{
return run_my_c_main( argc, argv );
}

Using C++ library in C code

Yes, this is certainly possible. You will need to write an interface layer in C++ that declares functions with extern "C":

extern "C" int foo(char *bar)
{
return realFoo(std::string(bar));
}

Then, you will call foo() from your C module, which will pass the call on to the realFoo() function which is implemented in C++.

If you need to expose a full C++ class with data members and methods, then you may need to do more work than this simple function example.

Use C library in a C++ code with non-compatible code

A straightforward (though perhaps not the only) solution:

Write a thin C++ bindings shim for your C library.

Since your library contains C code which is not C++-compatible - not in the common subset of both languages - you have to write bindings which C++ can use. These will need to be written in C, not in C++.

Let's call the bindings shim files you write frr_cpp_bindings.h and frr_cpp_bindings.c.

The shim's header file, frr_cpp_bindings.h, will expose essentially the same thing as libfrr.h, but without any actual code ( like ./r.inf = &_frrmod_info ) - only function and type definitions which are in the common subset of C++ and C.

The implementation of this shim (frr_cpp_bindings.c) will include libfrr.h directly and basically just forward calls to to libfrr.h-exposed C functions.

Finally, in the frr_cpp_bindings.h file, you can have something like this:

#ifdef __cplusplus
extern "C" {
#endif

// all of the actual C code

#ifdef __cplusplus
}
#endif

and this means you won't need to extern "C" in the C++ code.

Finally, so your C++ source files will have:

#include <frr_cpp_bindings.h>

and will not try to include the incompatible header directly.

Where/When to link against the Standard C Library when compiling C programs?

Essentially every hosted C implementation requires you to link programs with an implementation of the standard C library.

Some commands for building programs have the inclusion of the standard C library built-in as a default, so you do not need to add it explicitly on the command library. Some commands do not have it as a default, so you do need to add it on the command line.

How to use a C library from D?

It is possible to call C libraries from D. What you need to do is to convert the C header files to D. For the most part this is pretty straightforward, and there is a hard-to-use command-line tool to help automate the process. It's never really worked for me on anything but toy examples, but it could be a good start to see the kind of transformations that need to be done. Just put a snippet you're having trouble translating into a header by itself and see what htod does with it.

The biggest problem you'll usually encounter is creative use of the C preprocessor. Some things can be turned into version() statements in D, but not all.

As for actually compiling and linking with the code, on unix-like platforms I think you can compile and link in the C code using GCC. On Windows you either have to compile the C files using DMC and link with DMD. Or you can compile the C code into a DLL using any compiler capable of that, and then to link with DMD you need to make a DMD-compatible import lib out of the DLL. This can be done using the implib tool found in the free Basic Utilities Package available from DigitalMars.

There are also a lot of these header translations have already been done. It's useful to browse the Bindings project of Dsource first, or ask on the digitalmars D newsgroups first before embarking on something big like translating GTK headers. A lot of popular libraries like GTK have already been wrapped (e.g. here: GTKD)

Can I use shared library created in C++ in a C program?

You want something more like this (and here I will use a slightly more meaningful example):

C/C++ header - animal.h

#ifndef ANIMAL_H
#define ANIMAL_H

#ifdef __cplusplus
class Animal {
public:
Animal() : age(0), height(0) {}
Animal(int age, float height) : age(age), height(height) {}
virtual ~Animal() {}

int getAge();
void setAge(int new_age);

float getHeight();
void setHeight(float new_height);

private:
int age;
float height; // in metres!
};
#endif /* __cplusplus */

#ifdef __cplusplus
extern "C" {
#endif
struct animal; // a nice opaque type

struct animal *animal_create();
struct animal *animal_create_init(int age, float height);
void animal_destroy(struct animal *a);

void animal_setage(struct animal *a, int new_age);
void animal_setheight(struct animal *a, float new_height);
int animal_getage(struct animal *a);
float animal_getheight(struct animal *a);
#ifdef __cplusplus
}
#endif

#endif /* ANIMAL_H */

C++ animal implementation file - animal.cpp

#include "animal.h"
#define TO_CPP(a) (reinterpret_cast<Animal*>(a))
#define TO_C(a) (reinterpret_cast<animal*>(a))

void Animal::setAge(int new_age) { this->age = new_age; }
int Animal::getAge() { return this->age; }
void Animal::setHeight(float new_height) { this->height = new_height; }
float Animal::getHeight() { return this->height; }

animal *animal_create() {
animal *a = TO_C(new Animal);
return a;
}

animal *animal_create_init(int age, float height) {
animal *a = TO_C(new Animal(age, height));
return a;
}

void animal_destroy(animal *a) {
delete TO_CPP(a);
}

void animal_setage(animal *a, int new_age) {
TO_CPP(a)->setAge(new_age);
}

void animal_setheight(animal *a, float new_height) {
TO_CPP(a)->setHeight(new_height);
}

int animal_getage(animal *a) {
TO_CPP(a)->getAge();
}

float animal_getheight(animal *a) {
TO_CPP(a)->getHeight();
}

C client code - main.c

#include "animal.h"
#include <stdio.h>

int main()
{
// 6'0" 25yo (perhaps a human? :P)
struct animal *a = animal_create(25, 1.83);

animal_setage(a, 26); // birthday
printf("Age: %d\nHeight: %f", animal_getage(a), animal_getheight(a));

animal_destroy(a);
return 0;
}

C++ client code - main.cpp

#include "animal.h"
#include <iostream>

int main()
{
// 6'0" 25yo (perhaps a human? :P)
Animal* a = new Animal(25, 1.83);
a->setAge(26); // birthday
std::cout << "Age: " << a->getAge() << std::endl;
std::cout << "Height: " << a->getHeight();

delete a;
return 0;
}

So when you compile the library, you compile animal.cpp with a C++ compiler. You can then link to it with C code, and use the animal_xxx functions.

Note the use of struct animal and Animal. Animal is a normal C++ type. It's exactly what it looks like. struct animal, on the other hand, is an "opaque" type. That means that your C program can see it's there, and can have one, but it doesn't know what is inside it. All it knows is that it has a function that takes a struct animal*.

In a real library you will want to have customisation points for memory allocation. So assuming this is the library libjungle, you probably want at least jungle_setmalloc and jungle_setfree with sensible defaults. You can then set up the global new and delete in libjungle's C++ code to use these user-defined functions.



Related Topics



Leave a reply



Submit