命名空间嵌套函数的最佳实践和语义以及 extern“C”的使用
我正在创建一个带有 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)。
- 重整输出是标准行为吗——其他主要编译器(特别是 MSVC)也会剥离重整吗?
- 当涉及外部 ABI 时,将函数放置在命名空间中是否存在任何陷阱或最佳实践?
- 这会在链接期间干扰去重整函数的 C-ABI 导出吗?
I am creating a C++ library with a C-ABI interface.
This is how GCC treats the extern "C" qualifier with regards to mangling:
namespace x {
extern "C" int monkey(int x) {
return 1;
}
int chimpanzee(int x) {
return 1;
}
}
The relevant nm
output:
00000000004005cd T _ZN1x10chimpanzeeEi
00000000004005bf T monkey
Question:
I want to leave functions which are involved in the C-ABI inside a namespace, for maximum flexibility for reuse. Important Note: Once the library has been compiled I will give the linker a map file (GCC) or a module definition file (MSVC).
- Is the mangling output standard behaviour -- will other major compilers (MSVC in specific) strip mangling as well ?
- are their any pitfalls or best-practises regarding placing functions in a name-space when they are involved in an external ABI?
- Will this interfere with the C-ABI export of the de-mangled functions during link time ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你所做的一切都很好,并且会给你带来你想要的效果。来自The C++ 编程语言,第 3 版,第 208 页:“具有 C 链接的名称可以在名称空间中声明。名称空间将影响在 C++ 程序中访问名称的方式,但不会影响名称空间。链接器看待它的方式是
std
中的printf()
......即使使用std::printf()
调用,它仍然是旧的 Cprintf()
。”What you're doing is fine and will give you the effects that you want. From The C++ Programming Language, 3rd Edition, page 208: "A name with C linkage can be declared in a namespace. The namespace will affect the way the name is accessed in a C++ program, but not the way a linker sees it. The
printf()
fromstd
is a typical example. … Even when called withstd::printf()
, it is still the same old Cprintf()
."这是针对 MSVC 的。
命名空间本身不会被名称修改,但当发生名称修改时,命名空间的名称会合并到函数(或对象)的名称中。此过程没有记录,但在此处进行了描述。
通过跳来跳去回答您的具体问题:
1)没有关于名称修改的标准定义行为。该标准实际上所说的是,实现为
extern "C"
构造提供了 C 兼容的链接:7.5.3 [链接规范]
最终这意味着,由于 C 没有
命名空间
的概念,如果extern "C"
函数或命名空间中的对象,您导出的名称将丢失命名空间资格。这会导致...3) 是的,您可能会遇到链接问题。试试这个:
main.h
main.cpp
这将发出链接器错误,因为
x::foo()
和y 的
丢失了它们的命名空间标识,因此它们最终具有完全相同的名称:extern "C"
版本::foo()foo()
2) 与此相关的最佳实践。如果必须为命名空间中的函数导出 C-ABI,则必须小心最终导出的名称不相同。在某种程度上,这违背了使用
命名空间
的初衷。但你可以这样做:This is for MSVC.
The namespace itself is not name-mangled, but the name of the namespace is incorporated in to the function's (or object's) name when name mangling occurs. This process is undocumented, but described here.
Answering your specific questions by jumping around:
1) There is no Standard-defined behavior regarding name mangling. What the Standard actually says is that implementations provides a C-compatible linkage for
extern "C"
constructs:7.5.3 [Linkage specifications]
Ultimately what this means is that since C has no concept of
namespace
s, ifextern "C"
functions or objects in namespaces, your exported names will lose the namespace qualification. This leads to...3) Yes, you can have a linkage problem. Try this:
main.h
main.cpp
This will emit a linker error because the
extern "C"
-ed versions ofx::foo()
andy::foo()
have lost their namespace identification, so they end up with exactly the same name:foo()
2) Best practices regarding this. If you must export a C-ABI for functions in namespaces, you have to be careful that the names you end up exporting are not the same. To some degree, this defeats the purpose of using a
namespace
in the first place. But you can do something like this: