我正在创建一个带有C-ABI接口的C ++库。
这就是GCC如何处理关于破坏的外部“C”限定词:
namespace x {
extern "C" int monkey(int x) {
return 1;
}
int chimpanzee(int x) {
return 1;
}
}
相关的nm
输出:
00000000004005cd T _ZN1x10chimpanzeeEi
00000000004005bf T monkey
问题: 我想在命名空间中保留C-ABI中涉及的函数,以便最大程度地重用。 重要说明:编译库后,我将为链接器提供映射文件(GCC)或模块定义文件(MSVC)。
答案 0 :(得分:5)
你正在做的事情很好,会给你想要的效果。从 C ++编程语言,第3版,第208页:“可以在命名空间中声明具有C链接的名称。命名空间将影响在C ++程序中访问名称的方式,但不会影响链接器看到它的方式。来自printf()
的{{1}}是一个典型的例子....即使用std
调用,它仍然是旧的C std::printf()
。“
答案 1 :(得分:2)
这适用于MSVC。
名称空间本身不受名称限制,但在发生名称重整时,名称空间的名称会合并到函数(或对象)的名称中。此过程未记录,但描述为here。
通过跳转来回答您的具体问题:
1)没有关于名称重整的标准定义行为。标准实际上说的是实现为extern "C"
构造提供了C兼容的链接:
每个实施都应规定 链接到C中写的函数 编程语言,“C”和链接 到C ++函数,“C ++”。 [实施例:
complex sqrt(complex); // C + + linkage by default
extern "C" { double sqrt(double); // C linkage }
-end example]
最终这意味着由于C没有namespace
的概念,如果extern "C"
函数或命名空间中的对象,导出的名称将失去名称空间限定。这导致......
3)是的,你可能会遇到链接问题。试试这个:
#ifndef MAIN_API
# define MAIN_API __declspec(dllexport)
#endif
namespace x
{
extern "C" MAIN_API void foo();
};
namespace y
{
extern "C" MAIN_API void foo();
};
#include <cstdlib>
#include <iostream>
using namespace std;
#define MAIN_API __declspec(dllexport)
#include "main.h"
void x::foo()
{
cout << "x::foo()\n";
}
void y::foo()
{
cout << "y::foo()\n";
}
int main()
{
}
这将发出链接器错误,因为extern "C"
版本的x::foo()
和y::foo()
已丢失其名称空间标识,因此它们最终具有完全相同的名称:{{1 }}
2)关于此的最佳做法。如果必须为命名空间中的函数导出C-ABI,则必须注意最终导出的名称不同。在某种程度上,这首先违背了使用foo()
的目的。但你可以这样做:
namespace