33
namespace someNameSpace {
    extern "C" void doSomething()
        {
             someOperations();
        }
}

I want to run doSomething() in both C++ and C environment.

Is someNameSpace still encapsulating doSomething() if I expose it to extern "C" linkage?

Is there a good way to share functions between C++ and C while avoiding polluting global namespace on C++ side?

Edit: Because this code is primarily used in C++ mode, while the C linkage is for test use only, I guess this is a better way to do it.

namespace someNameSpace {
    #ifdef COMPILE_FOR_C_LINKAGE
    extern "C"
    #else
    extern "C++"
    #endif
    { 
        void doSomething()
            {
                 someOperations();
            }
    }
}
user3528438
  • 2,737
  • 2
  • 23
  • 42

3 Answers3

34

Your code works, but you should beware that all functions that have extern "C" linkage share the same space of names, but that is not to be confused with the C++ notion of "namespace": Your function is really someNameSpace::doSomething, but you cannot have any other extern "C" function with unqualified name doSomething in any other namespace.

See 7.5/6:

At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for a variable with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same variable. An entity with C language linkage shall not be declared with the same name as a variable in global scope, unless both declarations denote the same entity; no diagnostic is required if the declarations appear in different translation units. A variable with C language linkage shall not be declared with the same name as a function with C language linkage (ignoring the namespace names that qualify the respective names); no diagnostic is required if the declarations appear in different translation units. [Note: Only one definition for an entity with a given name with C language linkage may appear in the program (see 3.2); this implies that such an entity must not be defined in more than one namespace scope. — end note]

Your company's or project's global style arbiters should be able to advise you on a suitable naming policy for your code base.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • An entity with C language linkage shall not be declared with the same name as a variable in global scope, unless both declarations denote the same entity; ---- Is this a "entity vs variable" statement? I experimented with g++ 4.3.3 and it seems true. Conflict occurs only when I re-declare an global variable like "extern int doSomething=1;" but it's OK if I define another "extern void doSomething(){}" as long as it's not another extern C linkage. – user3528438 Mar 11 '15 at 21:09
20

Just piece of code to illustrate behavior stated in Kerrek SB answer

#include <iostream>

namespace C{
    void Hello(){
        std::cout<<"Hello"<<std::endl;
    }
    extern "C" void HelloThere(){
        std::cout<<"Hello There from extern \"C\""<<std::endl;
    }
}

extern "C" void HelloThere();

int main() {
    C::Hello();
    C::HelloThere(); //Compiles
    //Hello(); <--- does not compile
    HelloThere(); //Also compiles and prints the same as C::HelloThere() !!!

    return 0;
}

Live at http://ideone.com/X26wfR

albusshin
  • 3,930
  • 3
  • 29
  • 57
Chajnik-U
  • 501
  • 4
  • 8
4

In C++ ABI, namespaces have to be mangled. So this:

namespace foo
{
    void bar(int){}
}

is translated more or less to such symbol:

foo::bar(int)

When you force the compiler to use C ABI, the similar symbol

namespace foo
{
    extern "C" void bazz(int){}
}

after compilation looks like following:

bazz

You can see the difference in the godbolt: https://godbolt.org/z/BmVpSQ

In C ABI there are no namespaces or argument list mangled with the function, so you can only have 1 such symbol in the whole code. Defining it twice:

namespace foo
{
    extern "C" void bazz(int){}
}

namespace foo2
{
    extern "C" void bazz(int){}
}

int main()
{
    foo2::bazz(5);
    return 0;
}

...is illegal. The clang compiler just emits simple compilation error in such case:

https://wandbox.org/permlink/r5CUXm7OKePtG35L

The gcc compiler emits error too, but it looks way more misterious:

https://wandbox.org/permlink/BiN0auna9klBg5GE

Mariusz Jaskółka
  • 4,137
  • 2
  • 21
  • 47
  • Not sure if it was different at the time this answer was posted, but gcc seems to be emitting an error during compilation when I clicked the link (interestingly, at the assembly stage, which is I think the first time I've ever seen an error in that stage of compilation) – Dominick Pastore Aug 10 '20 at 16:30
  • @DominickPastore you are right - edited the error message is very strange though. I've edited the answer. – Mariusz Jaskółka Aug 11 '20 at 10:08