【问题标题】:problem wrapping extern "C" library in a namespace在命名空间中包装外部“C”库的问题
【发布时间】:2011-08-25 09:34:07
【问题描述】:

我正在使用来自 C++ 的 C 库 (libgretl),它的一些函数与我的代码冲突,所以我想将它包装在命名空间中,如下所示:

namespace libgretl {
extern "C" {
    #include <gretl/libgretl.h>
}}

但是,这无法编译,我从 gcc 文件中得到“未定义”错误(在 Windows 上使用 mingw32 和 gcc 4.5.2)。 第一个错误来自文件 c++/cstddef 的以下代码块:

_GLIBCXX_BEGIN_NAMESPACE(std)
  using ::ptrdiff_t;
  using ::size_t;
_GLIBCXX_END_NAMESPACE

宏分别扩展为namespace std {}。在这些之后还有更多错误。

省略extern "C" 指令没有帮助。使用匿名命名空间可减少错误数量,但仍无法编译。

因此,我的问题是,是否有某种方法可以包含这样的 C 库并将其函数放入命名空间,而不更改 gcc 或库的源文件?

谢谢。

迈克尔

【问题讨论】:

  • 我认为简短的回答是否定的
  • 问题可能是gretl/libgret1.h 包含stddef.h,因此您在命名空间中间接包含标准标头,这是一个禁忌。

标签: c++ namespaces


【解决方案1】:

你做不到。命名空间不仅仅是源代码装饰,它们还被编译器修改为对象符号。

库中的原生 C 函数 foo() 将通过目标文件中的符号 _foo 可用,但调用 bar::foo() 将生成对例如 @N3barfoo 的引用。结果会出现链接器错误。

您可以在单独的源文件中创建“代理”函数,包括仅在此源中的原始库头并将所有代理函数放入命名空间。

【讨论】:

  • 我想我明白你在说什么,但它没有解释两件事:为什么它可以与另一个 C 库(我自己的,比 libgretl 简单得多)一起工作?为什么它在编译时失败 - 名称修改问题不会首先出现在链接器中吗?
  • 尝试查看预处理的源代码,gcc 将使用 -E 开关输出它。可能在 C 标头中有一些 #defines 会破坏以后的编译(#define namespace ..., f.e.)
  • 不,命名空间只被使用(就像在原始帖子中一样),从未定义或以其他方式破坏
  • 那我就不知道了:(猜猜 'extern "C" inside namespace' 在编译器中实现得不是很好。
【解决方案2】:

您不能简单地将命名空间包装在外部声明周围并让它出现在该命名空间中......项目(函数,全局)必须从一开始就在该命名空间中构建。由于 C 不支持命名空间解析,因此不可能是这种情况。

您需要更改自己的代码以适应此库,除非您愿意为库本身唱诵。

要引用与您自己的命名空间项目冲突的非命名空间项目,请参阅::item()

【讨论】:

    【解决方案3】:

    我猜 C 库被编译为 C,这意味着命名空间不包含在编译代码中,也不支持。因此,您编译的 C 库不能位于命名空间中。通过封装包含来更改标头不会改变这一点。

    您仍然可以将自己的代码封装在命名空间中。

    【讨论】:

    • 奇怪 - 我为另一个 C 库执行此操作,它在那里工作。我天真地认为 C 代码“不会看到”命名空间,即它只会影响封装的 C++ 代码..
    • 至于将我自己的代码封装在命名空间中 - 我这样做是因为一些库的定义与我的命名空间名称冲突:-(
    • @Michal Kaut:那么您需要指定要调用哪个函数:::foo(); 将引用全局命名空间中的foo(),而foo();将按照通常的规则挑选第一场比赛。
    • @dribeas 不确定:该库定义了一个名为 PCA 的常量,而我的代码有一个名为 PCA 的命名空间;因此,编译在它达到第二个定义时失败,即在我使用这两个对象中的任何一个之前。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    相关资源
    最近更新 更多