【问题标题】:Which one is the better - calling c++ library from c program?哪个更好 - 从 c 程序调用 c++ 库?
【发布时间】:2015-02-23 08:45:52
【问题描述】:

我有 c++ 库 .so。我的同事正在开发 c 程序,该程序将从他的 c 程序中调用 c++ 库。我告诉他创建 Wrapper.h 和 Wrapper.cpp 并使用指针在他的 c 程序中传递 c++ 对象。但是,我发现他试图通过将 Wrapper.cpp 和 header 直接添加到我们的库 .so 中来修改我们的 c++ 库源代码。例如:

class A{ SetValueA(int); }
class B{ SetValueB(int); }

在他的 Wrapper.cpp 中,他是这样写的:

A a;
B b;
extern "C" SetValueA(int) {a.SetValueA(int); }
extern "C" SetValueB(int) {b.SetValueB(int); }

然后他重新编译了我们的 c++ 库,并将 Wrapper.h 包含在他的 c 程序中。

我告诉他的是这样做: 在我的 Wrapper.cpp 中

extern "C" {
    A* newClassA() {
            return new A();
    }

    void SetValueA(A* v, int i) {
            v->SetA(i);
    }
    B* newClassB() {
            return new B();
    }

    void SetValueB(B* v, int i) {
            v->SetB(i);
    }

    void deleteClassA(A* v) {
            delete v;
    }
    void deleteClassB(B* v) {
            delete v;
    } }

然后我刚刚编译了我的 Wrapper.cpp 并与我们的 c++ 库链接。在他的 c 程序中,他只需要包含 Wrapper.h 并编译他的 c 代码,然后使用 c++ 编译器编译 Wrapper.o 和 main.o(来自 main.c)。

他的解决方案看起来也很有效,他抱怨说我告诉他的方式更有效。但我不希望他更改我们的 c++ 库,因为没有其他人会使用 c++ 库中的 Wrapper 类。你能告诉我哪个更好,为什么?

是的,我也不喜欢他在包装器中使用全局变量的方式。

【问题讨论】:

  • 我更喜欢他的解决方案,因为他只需要将 c++ 库与他的 c 程序链接起来,并且只调用 c 接口函数。使用您的解决方案,他必须链接到 c++ 库,并使用 c++ 编译器编译包装器,然后链接到两者。这一切都取决于您是否更喜欢编辑库以包含 c 接口,这是一个偏好。所以这完全取决于你们。
  • @Brandon:他需要链接到 C++ 库并创建一个 C++ 编译的包装文件。
  • 是的,但对于其中一个,他只是编辑库以包含一个 c 接口并重新编译它。然后他所要做的就是链接到它。第二种方式需要他制作包装器并链接到库以编译包装器。然后在他的 c 程序中,链接到包装器和库。至少我是这么理解的?还是我解释错了?
  • @Brandon:我认为实际上存在多个相互交织的问题:包装代码所在的组织就是其中之一。我对此没有太多意见,但我可以想象 C++ 库的 C 包装器成为库的一部分。另一个问题是包装器应该是什么样子,我对此有相当强烈的看法:全局变量总是不如其他方法。
  • @Brandon,我的解决方案需要使用与库链接的 g++ 编译 Wrapper.o,使用 gcc 编译 main.o,然后将 Wrappe.o 和 main.o 与与库链接的 g++ 结合起来,但我的库提供通用 c++ API。没有其他人会使用他图书馆里的 Wrapper。

标签: c++ c


【解决方案1】:

我不明白为什么需要更改任何库文件以使用全局变量:必要的更改应仅限于 Wrapper.cpp,这显然是包装器的一部分。

也就是说,我不相信使用任何 [可变] 全局对象。它们往往以许多不同的方式成为问题。也就是说,我同意创建包装器的正确方法是有效地处理必要的生命周期管理。我确实意识到,在 C 中正确排序终生管理比在 C++ 中更难。对此的解决方法是使用 C++,而不是创建不必要的依赖项(我知道这个论点通常不适用于 C 程序员)。

【讨论】:

  • 是的,我也不喜欢他在 wrapper.cpp 中使用全局变量的方式。
【解决方案2】:

您的同事编写的包装器当然是不可分割的,因为使用了全局变量,这会在您的库中引入许多问题。

但是,我相信,一个编写良好的库应该自己导出一个 C 接口,即使它在内部使用 C++。原因很简单,C 接口可以导入几乎所有语言,而 C++ 接口要求用户代码是 C++。此外,在用户代码中强制使用这种包装器可能会导致不同 wrapper.cpp 版本的激增,所有这些版本都不完整且以不同的方式过时。

因此,我会将您的 wrapper.cpp 行中的代码包含到您的库中。而且我肯定会将它移到它包装的代码附近,而不是将它们全部捆绑在一个又大又胖的 wrapper.cpp 中。这样就更容易检查您的所有公共方法是否已正确包装。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 2016-06-11
    • 1970-01-01
    相关资源
    最近更新 更多