我有一个C库,我需要在C ++代码中使用,所以我需要用extern "C"
块包装整个lib。问题是该库似乎包含一个C ++编译的代码,因此包装整个lib也会包装该C ++头。
在lib.h
内部我只包含我要公开的所有内部标题,如下所示:
#ifndef LIB_H
#define LIB_H
#include "lib_foo.h"
#include "lib_bar.h"
#include "lib_baz.h"
#endif
因此客户端只需要包含lib.h
即可使用lib。
在我的第一次尝试中,我做到了这一点:
#ifndef LIB_H
#define LIB_H
extern "C" {
#include "lib_foo.h"
#include "lib_bar.h"
#include "lib_baz.h"
}
#endif
但是当我执行already_compiled_c++.h
内的任何函数时,我得到一个符号查找错误。
如何避免在extern "C"
头文件中应用already_compiled_c++.h
?
修改
解决。这不是使用extern "C"
的问题,将编译的c ++库与gyp正确链接是一个问题:Using shared library in Gyp in node-sqlite3
答案 0 :(得分:4)
请注意,extern C
不是合法的C,因此只能将其作为C ++编译。
already_compiled_c ++ .h标头可能包含针对多个包含的警戒,因此请先包含它:
#ifndef LIB_H
#define LIB_H
# This include added so that it won't get marked extern "C" when included by lob_foo.h.
#include <already_compiled_c++.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "lib_foo.h"
#include "lib_bar.h"
#include "lib_baz.h"
#ifdef __cplusplus
}
#endif
#endif
注意:您需要检查是否有条件地包含already_compiled_c++.h
并添加相应的条件。
答案 1 :(得分:2)
您无法从以普通C编译的文件中调用C ++。
如果lib_foo.h是普通的C,它不能直接使用already_compiled_c ++中的函数。您很可能需要为它创建一个C包装器。
这个答案可能会对您有所帮助:Elegantly call C++ from C
答案 2 :(得分:2)
如果您的图表准确无误,则lib_foo.h
不应包含already_compiled_c++.h
。编辑它以停止包括它。
如果在already_compiled_c++.h
中声明的函数将其实现编译为使用C ++ ABI,则C程序无法链接它们。 (除了非常丑陋的黑客攻击)。
为了避免将来出现类似的问题,请在每个头文件中明确放置#ifdef __cplusplus
extern "C" {
防护,这些头文件将具有C实现,但可能在C ++程序中使用,反之亦然。< / p>
当前情况的解决方法是制作一个.cpp
文件,其中包含您需要的功能。在extern "C"
下发布您的thunk,并通过调用already_compiled_c++.h
中的函数来实现它们。
答案 3 :(得分:1)
重新考虑你的设计。您不能包含C中的C ++标头,只能反过来。一些建议:
1)虽然'extern“C”'背后的原始想法是包含来自C ++文件的C头文件,但是如果你的头文件应该是C可访问的但是用C ++实现,那么常见的方法是包装声明在其中,而不是包含。 (使用必需的#ifdef __cplusplus,因此C代码总是将标题视为C,不会阻塞不需要的C ++ - ism'extern“C”')
2)不要将C ++公开为库的公共API。 C ++通常不提供二进制稳定的ABI。如果你添加一个方法并且它不在最后,或者你将一个实例变量添加到一个类中,或者你在一个模板化的类中更改某些东西,那么所有的客户端都必须重新编译(通常会发生静态库,但是这是dylibs / DLLs / frameworks的一个大问题。因此,一般来说,最好的想法是将C ++保留为实现细节,并仅从库中公开C函数。
3)如果需要从库中公开C ++,请使用Pimpl(私有实现)模式而不使用模板,并将其放在主C头未包含的单独头中,这样C客户端就可以了不包括它。这样一个单独的头对#2也很有用,因为你的库的模块实现文件(用C ++编写)可以包含它,从而使用它中的类。
4)对于C ++,指向结构Foo的指针和指向类Foo的指针是相同的。因此,如果您需要从C ++中幕后实现的C-only API返回C ++类,那么您可以做的只是始终在头文件中使用struct Foo *(C正确理解),并为C ++提供C包装函数。类的方法如:
extern "C" int FooGetCount( struct Foo* thisFoo )
{
return thisFoo->GetCount();
}
这样他们就可以保留指向C ++对象的指针并访问它们的属性,但不需要实际使用C ++。当然,您还需要提供类似的包装器来创建/删除对象,因为C没有新的/删除操作符。