Best Practise and Semantics of namespace nested functions and the use of extern “C”

StackOverflow https://stackoverflow.com/questions/4186165

  •  10-10-2019
  •  | 
  •  

Question

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).

  1. Is the mangling output standard behaviour -- will other major compilers (MSVC in specific) strip mangling as well ?
  2. are their any pitfalls or best-practises regarding placing functions in a name-space when they are involved in an external ABI?
  3. Will this interfere with the C-ABI export of the de-mangled functions during link time ?
Was it helpful?

Solution

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]

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]

Ultimately what this means is that since C has no concept of namespaces, if extern "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

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

This will emit a linker error because the extern "C"-ed versions of x::foo() and y::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:

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

OTHER TIPS

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() from std is a typical example. … Even when called with std::printf(), it is still the same old C printf()."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top