I have a dll whose source code is written in C++ . I would like to create the static version of that library and I would like to be able to link this static library in a another library which is written in pure C. The compiler is MinGW on Windows. How should I compile the first C++ static library so to make it usable by a C library?
问题:
回答1:
If you plan on calling member functions of an instance of C++ class you will need to provide forwarding functions. You will also need to provide at least one function to return a pointer to an instance of the class you want to access. There are to significant reasons for this. 1) Constructors are special and do not have names so they cannot be called directly and 2) member functions take an implicit this
parameter which can be passed on the stack or in a register.
For instance let's say you have a class called SomeClass
#include <iostream>
class SomeClass
{
public:
void Print(int value) { std::cout << value << std::endl; }
void Print(const char *value) { std::cout << value << std::endl; }
};
Now, you want to add a type safe way of creating and accessing an instance of that class. You can create a C interface that provides the creation function and forwarding functions. You might start by adding an additional header file to provide the C interface for SomeClass
XSomeClass.h
#ifdef __cplusplus
extern "C"
{
#endif
// C type representing SomeClass. This adds some type safety to it's use in C
typedef struct XSomeClass XSomeClass;
// This will create an instance of SomeClass and return a pointer to XSomeClass
XSomeClass* SomeClass_Create( );
// forwarding calls to access member functions of SomeClass. These calls take
// an explicit pointer to XSomeClass as the first parameter. self points to
// an instance of SomeClass returned by SomeClass_Create()
void SomeClass_PrintInt(XSomeClass* self, int value);
void SomeClass_PrintString(XSomeClass* self, const char *value);
#ifdef __cplusplus
}
#endif
Now you need to provide an implementation of the C interface. This is where all the magic happens that allows you to call C++ member functions from C.
XSomeClass.cpp
extern "C" XSomeClass* SomeClass_Create()
{
return reinterpret_cast<XSomeClass*>(new SomeClass());
}
extern "C" void SomeClass_PrintInt(XSomeClass* self, int value)
{
reinterpret_cast<SomeClass*>(self)->Print(value);
}
extern "C" void SomeClass_PrintString(XSomeClass* self, const char *value)
{
reinterpret_cast<SomeClass*>(self)->Print(value);
}
I recommend using reinterpret_cast
over C style casts to prevent the accidental removal of const
qualifiers.
To access the C++ library from C you can now do something like the example below
main.c
#include "XSomeClass.h"
int main(int, char**)
{
XSomeClass *sc = SomeClass_Create();
SomeClass_PrintInt(sc, 1);
SomeClass_PrintString(sc, "hello");
}
Note: Simply putting the C++ library in a DLL and calling GetProcAddress
for free functions and static member functions will be difficult as you will need to take into account name mangling.
回答2:
You don't, you do the opposite. You make the C library work in your C++ program. C++ encompasses C, not the other way around (superset C++, subset C). So what you do, is you can write a C++ program (using C++ or C syntax), and compile this program with a c++ compiler. You can then use C and C++ libraries.
回答3:
You add a C API to your C++ library. In the header file you add
#ifdef __cplusplus
extern "C" {
#endif
.
.
.
#ifdef __cplusplus
}
#endif
You do the same in your C api C++ file "but you can leave out the #ifdef
s because you know you will be compiling them using your C++ compiler.
You C api C++ file then can access the C++ API but your library is guaranteed to export using the C style Application Binary interface (no name mangling). The library can then be used from a C application.
The header file will be good to go both in C and C++ projects