命名空间嵌套函数的最佳实践和语义以及extern的使用;"; 我正在创建一个带有C-ABI接口的C++库。

命名空间嵌套函数的最佳实践和语义以及extern的使用;"; 我正在创建一个带有C-ABI接口的C++库。,c++,portability,abi,C++,Portability,Abi,这是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处理外部“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导出被破坏的功能

  • 你所做的很好,会给你想要的效果。从C++编程语言,第三版,第208页:“一个名字有C链接的名字可以在命名空间中声明。命名空间会影响C++程序中名字的访问方式,但不是链接器看到它的方式。<代码> Prtff())/<代码>从代码> STD< /Cord>是一个典型的例子……即使在调用了<代码> STD::Prtff()时,也会出现一个典型的例子。,它仍然是原来的C
    printf()

    这是用于MSVC的

    名称空间本身没有名称损坏,但名称空间的名称在名称损坏时会合并到函数(或对象)的名称中。此过程未记录,但已描述

    通过跳转回答您的具体问题:

    1) 没有关于名称损坏的标准定义行为。标准实际上说的是,实现为
    extern“C”
    构造提供了一个与C兼容的链接:

    7.5.3[联动装置规范] 每项实施应规定: 链接到用C语言编写的函数 编程语言“C”和链接 对于C++函数,“C++”。[示例:

    -[结束示例]

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

    3) 是的,您可能有链接问题。试试这个:

    main.h main.cpp
    谢谢,我很高兴这些陷阱相对简单,而且通常是常识性的——也许我会在构成c-ABI接口的函数上使用c风格的前缀。
    complex sqrt(complex); // C + + linkage by default 
    extern "C" { double sqrt(double); // C linkage } 
    
    #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()
    {
    }
    
    #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();
    };