【问题标题】:extern C return class objectextern C 返回类对象
【发布时间】:2013-01-27 15:35:11
【问题描述】:

我想要一个插件,名称更简单,可以在其他 C++ 代码中解析。

class B {
};

extern "C" B foo(); // to avoid name mangling in order to be loaded by dlsym

而在程序的另一部分(也是在 C++ 中并与插件共享相同的 B 类定义):

B (*func)();
func = dlsym("/path/to/so", "foo");
B m = func();

这样的代码是否会引起任何问题,即是否允许(按标准)在 extern "C" 函数中使用 C++ 类作为参数或返回类型?它似乎适用于我的 gcc,但其他的呢?

【问题讨论】:

  • 我认为您的代码没有任何问题。
  • 为什么除了[C++]之外还标有[C]?这个问题似乎只涉及 C++。如果我们还必须考虑 C 语言,问题的性质就会发生巨大变化。
  • 请注意,dlsym() 采用从 dlopen() 返回的句柄,而不是共享库的路径名。

标签: c++ c extern-c


【解决方案1】:

这应该可行,但有几个条件:

  • 如果您打算将 B 类的定义转换为其他内容,则它不会起作用。您唯一可以更改的是 foo() 的定义。
  • 插件和加载程序都必须在二进制级别上就类 B 的接口达成一致。切换编译器(包括版本和一些标志)可以改变这个接口。
  • 您显然必须在 C++ 中强制转换 dlsym() 的返回值。
  • 不能在 C 中使用类。

【讨论】:

    【解决方案2】:

    将 foo() 声明为 extern "C" 当然将允许您通过 dlsym() 使用实际的、未修改的函数名称来加载它,但否则不会影响您在加载后如何使用该函数。

    通常的规则仍然适用。如果你破坏了 foo() 或 B 类的二进制兼容性,你将需要重新编译插件,就像如果它是一个常规的、非运行时加载的动态库你必须重新编译它一样。

    【讨论】:

      【解决方案3】:

      只要您坚持使用 C++ 并且仅使用 C++,它就会起作用。由于显而易见的原因,您将无法在 C 翻译单元中编译您的函数声明。 (也就是说,你永远无法正确地向 C 编译器解释 B 是什么。)

      所以,我在这里看到的唯一问题是 [C] 标签在您的问题上的含义是什么。您还需要某种与 C 的交叉兼容性吗?

      【讨论】:

        猜你喜欢
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        • 2013-10-26
        • 2021-09-29
        • 1970-01-01
        • 2013-10-30
        • 1970-01-01
        • 2019-12-22
        相关资源
        最近更新 更多