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
How to Avoid the Diamond of Death When Using Multiple Inheritance
Scope of Variables in If Statements
Boost C++ Serialization Overhead
Static Variables in an Inlined Function
Relative Performance of Std::Vector VS. Std::List VS. Std::Slist
Move-Only Version of Std::Function
Number of Combinations (N Choose R) in C++
Error Lnk2005: Already Defined - C++
Stdafx + Header File - Order of Inclusion in Mfc Application
Are Child Processes Created with Fork() Automatically Killed When the Parent Is Killed
About Binding a Const Reference to a Sub-Object of a Temporary
Is Storing an Invalid Pointer Automatically Undefined Behavior
Linker Error When Calling a C Function from C++ Code in Different VS2010 Project
Preparation for Std::Iterator Being Deprecated
C++ Equivalent to Java's Blockingqueue