c – 命名空间嵌套函数的最佳实践和语义以及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导出?

最佳答案
这适用于MSVC.

命名空间本身不受名称限制,但在发生名称重整时,命名空间的名称将合并到函数(或对象)的名称中.此过程未记录,但描述为here.

跳转回答你的具体问题:

1)关于名称重整没有标准定义的行为.标准实际上说的是实现为extern“C”构造提供了C兼容的链接:

7.5.3 [链接规范]

Every implementation shall provide for
linkage to functions written in the C
programming language, “C”, and linkage
to C + + functions, “C++”. [Example:

complex sqrt(complex); // C + + linkage by default 
extern "C" { double sqrt(double); // C linkage } 

—end example]

最终这意味着由于C没有命名空间的概念,如果extern“C”函数或命名空间中的对象,导出的名称将失去命名空间限定.这导致…

3)是的,你可能会遇到链接问题.试试这个:

main.h

#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();
};

main.cpp中

#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()
{
}

这将发出链接器错误,因为x :: foo()和y :: foo()的extern“C”版本已经丢失了它们的名称空间标识,因此它们最终具有完全相同的名称:foo()

2)关于此的最佳做法.如果必须为命名空间中的函数导出C-ABI,则必须注意最终导出的名称不同.在某种程度上,这首先破坏了使用命名空间的目的.但你可以这样做:

#ifndef MAIN_API
#   define MAIN_API __declspec(dllexport)
#endif

namespace x
{
    extern "C" MAIN_API void x_foo();
};

namespace y
{
    extern "C" MAIN_API void y_foo();
};

转载注明原文:c – 命名空间嵌套函数的最佳实践和语义以及extern“C”的使用 - 代码日志