简体   繁体   English

如何从C调用用C ++编写的lib?

[英]How to call a lib written in C++ from C?

It seems to me like a no-brainer, but I cannot find any information against or for it. 在我看来,这似乎是一个明智的选择,但我无法找到任何反对或为此的信息。

From the point of view of demangling etc, I don't suppose this to be a big problem, but I can't figure out, how I can write a little tiny C program which calls a function from a little tiny C++ library. 从demangling等的角度来看,我不认为这是一个大问题,但我无法弄清楚,我怎么能写一个小C程序从一个小小的C ++库调用一个函数。

I am on linux right now, trying with static binding. 我现在在linux上,尝试使用静态绑定。

This must be something many people are running into or many books cover, but I feel like a blind gump sitting in front of this problem. 这肯定是许多人遇到的事情或许多书籍所涵盖的事情,但我觉得这是一个坐在这个问题面前的盲人。 Interestingly, there is no such question on SO either. 有趣的是,在SO上也没有这样的问题。

I do not even know IF this can work, far lesser HOW this has to be done. 我甚至不知道如果这可以工作,那么必须如何做得更少。

Typically, you need to force the C++ compiler to build the library with C linkage for the exported functions. 通常,您需要强制C ++编译器为导出的函数构建具有C链接的库。

You can do that by doing the following to your header: 您可以通过对标题执行以下操作来执行此操作:

#ifdef __cplusplus
extern "C" {
#endif

void func(void);

/* ... Other function defs go here ... */

#ifdef __cplusplus
}
#endif

Normally, the linker will do C++ name-mangling to the functions, so that the C linker won't be able to find them. 通常,链接器将对函数执行C ++名称修改,以便C链接器无法找到它们。 extern "C" forces it not to do that. extern "C"迫使它不这样做。 You need to wrap it in the #ifdef , because extern "C" isn't valid in C. 你需要将它包装在#ifdef ,因为extern "C"在C中无效。

UPDATE UPDATE

As Charles Salvia says in a comment below, you need to ensure that no exceptions make their way out through your interface, because C has no way of handling them (at least not a platform-independent way). 正如Charles Salvia在下面的评论中所说,你需要确保没有异常通过你的界面出来,因为C无法处理它们(至少不是与平台无关的方式)。

If the C++ library does not provide a C interface, then you can't. 如果C ++库没有提供C接口,那么你就不能。

If it does, use C interface. 如果是,请使用C接口。

If you are the author, use the extern "C" feature. 如果您是作者,请使用extern "C"功能。 http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html

Personally, I'd write a C++ file that exports functions that use C linkage. 就个人而言,我写了一个C ++文件,导出使用C链接的函数。 In other words, write a binding. 换句话说,写一个绑定。

It is a problem from the point of demangling. 从解码的角度来看这是一个问题。 Use extern C around the C++ you want to call from C. 在要从C调用的C ++周围使用extern C.

Mangling and de-mangling was never standardized in C++, since it was deemed too platform dependent. 在C ++中, Mangling和de-mangling从未标准化,因为它被认为太依赖于平台。 The result is, that while you could figure out the method name of a C++ method by looking at the linker output, there is no portable way of finding the "real" linkable name of a C++ method of function. 结果是,虽然通过查看链接器输出可以找出C ++方法的方法名称,但是没有可移植的方法来查找C ++函数方法的“真实”可链接名称。

On Linux, you can get the mangled name of your C++ functions with the command 在Linux上,您可以使用该命令获取C ++函数的错位名称

nm my-tiny-c++lib.a

Call the function from C by it's mangled name, but do not expect this trick to be portable... 通过它的受损名称从C调用函数,但不要指望这个技巧是可移植的......

Edit : then you have to link using g++, or with gcc -lstdc++ 编辑 :然后你必须使用g ++或gcc -lstdc ++进行链接

You can write a C wrapper around any C++ library that has a C++ API. 您可以在任何具有C ++ API的C ++库周围编写C包装器。 The wrapper should be written in C++. 包装器应该用C ++编写。

You can even use your C++ classes. 您甚至可以使用C ++类。 You forwardly declare them as struct. 你将它们声明为struct。 Some compilers will give a warning if you do this but you can probably either disable this warning or just ignore it. 如果您执行此操作,某些编译器会发出警告,但您可以禁用此警告或忽略它。

You now create free-functions to create a pointer to such a struct (not an instance, as you don't see its full definition) and to dispose of such a pointer and all its methods by taking it as a parameter. 您现在创建自由函数来创建指向这样的结构的指针(不是实例,因为您没有看到它的完整定义),并通过将其作为参数来处置这样的指针及其所有方法。

Note that if the class is in a namespace, you won't be able to do this so create your own struct that has just that member and use that "wrapper" instead. 请注意,如果类在命名空间中,您将无法执行此操作,因此请创建自己的结构,该结构只包含该成员并使用该“包装器”。

For all your C functions. 适用于所有C功能。 in the header only, put 只在标题中,放

#ifdef __cplusplus
extern "C" {
#endif

// all your functions

#ifdef __cplusplus
}
#endif

Typical wrapper looks like this: 典型的包装器看起来像这样:

---- class_a.hpp ---- ---- class_a.hpp ----

#include "class_a_wrapper"

class A {
     public:
     int foo(double p);
     double bar(int x, int y);
}

---- class_a_wrapper.h ---- ---- class_a_wrapper.h ----

#ifdef __cplusplus
extern "C" {
#endif

struct wrap_A;
int wrap_A_foo(struct wrap_A *obj, double p);
double wrap_A_bar(struct wrap_A *obj, int x, int y);

#ifdef __cplusplus
}
#endif

---- class_a_wrapper.cpp ---- ---- class_a_wrapper.cpp ----

#include "class_a.hpp"

int wrap_A_foo(struct wrap_A *obj, double p) {
    return (static_cast<A*>obj)->foo(p);
}
double wrap_A_bar(struct wrap_A *obj, int x, int y) {
    return (static_cast<A*>obj)->bar(x, y);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM