5

我有一个 dll,其源代码是用 C++ 编写的。我想创建该库的静态版本,并且希望能够将此静态库链接到另一个用纯 C 编写的库中。编译器是 Windows 上的 MinGW。我应该如何编译第一个 C++ 静态库以使其可供 C 库使用?

4

3 回答 3

9

如果您计划调用 C++ 类实例的成员函数,则需要提供转发函数。您还需要提供至少一个函数来返回指向您要访问的类的实例的指针。这有很重要的原因。1) 构造函数是特殊的并且没有名称,因此不能直接调用它们;2) 成员函数采用隐式this参数,该参数可以在堆栈寄存器中传递。

例如,假设您有一个名为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; }
};

现在,您想要添加一种类型安全的方式来创建和访问该类的实例。您可以创建一个提供创建功能和转发功能的C 接口。您可以首先添加一个额外的头文件来提供 C 接口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

现在您需要提供 C 接口的实现。这就是所有允许您从 C 调用 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);
}

我建议使用reinterpret_castover C 风格的强制转换来防止意外删除const限定符。

要从 C 访问 C++ 库,您现在可以执行以下示例

主程序

#include "XSomeClass.h"

int main(int, char**)
{
    XSomeClass *sc = SomeClass_Create();
    SomeClass_PrintInt(sc, 1);
    SomeClass_PrintString(sc, "hello");
}



注意:简单地将 C++ 库放在 DLL 中并调用GetProcAddress自由函数和静态成员函数将很困难,因为您需要考虑名称修改

于 2013-07-10T16:48:48.503 回答
2

您将 C API 添加到 C++ 库中。在您添加的头文件中

#ifdef __cplusplus
extern "C" {
#endif
.
.
.
#ifdef __cplusplus
}
#endif

你在你的 C api C++ 文件中做同样的事情“但是你可以省略#ifdefs 因为你知道你将使用你的 C++ 编译器来编译它们。

然后您的 C api C++ 文件可以访问 C++ API,但您的库保证使用 C 风格的应用程序二进制接口(无名称修改)导出。然后可以从 C 应用程序中使用该库。

头文件适用于 C 和 C++ 项目

于 2013-07-10T15:53:57.427 回答
1

你不这样做,你做相反的事情。您使 C 库在您的 C++ 程序中工作。C++ 包含 C,而不是相反(超集 C++,子集 C)。所以你要做的是,你可以编写一个 C++ 程序(使用 C++ 或 C 语法),然后用 C++ 编译器编译这个程序。然后,您可以使用 C 和 C++ 库。

于 2013-07-10T15:43:01.527 回答