views:

438

answers:

5

Hello,

I find such examples in Boost code.

namespace boost {
   namespace {
     extern "C" void *thread_proxy(void *f)
     {
       ....
     }

   } // anonymous
   void thread::thread_start(...)
   {
       ...
       pthread_create(something,0,&thread_proxy,something_else);
       ...
   }
} // boost

Why do you actually need this extern "C"?

It is clear that thread_proxy function is private internal and I do not expect that it would be mangled as "thread_proxy" because I actually do not need it mangled at all.

In fact in all my code that I had written and that runs on may platforms I never used extern "C" and this had worked as-as with normal functions.

Why extern "C" is added?


My problem is that extern "C" function pollute global name-space and they do not actually hidden as author expects.

This is not duplicate!

I'm not talking about mangling and external linkage. It is obvious in this code that external linkage is unwanted!

Answer: Calling convention of C and C++ functions are not necessary the same, so you need to create one with C calling convention. See 7.5 (p4) of C++ standard.

A: 

Probably because you are interfacing a plain C library -- pthreads.

Dirk Eddelbuettel
+4  A: 

extern "C" linkage does not necessarily mean that only name mangling is suppressed. In fact, there may be a compiler which treats extern "C" as a different calling convention.

The standard leaves this completely open as implementation-defined semantics.

greyfade
Can you give a name of any platform where C plain function calling convention is not compatible on ABI level with C++ one? Because at least on Alpha, Itanium, ARM, X86, x86_64 with I have never had any issues with different conventions.
Artyom
What does that have to do with anything? Do you want to write code which only works because you're closely acquainted with the calling conventions of every single C++ implementation that has ever been written, and apply that knowledge? Or do you want to write code that works on any implementation of the C++ standard, because you do what the standard says you must do for the result you want? In future, are you going to write to the standard because someone has pointed out an implementation that does require extern "C", or because in fact you are not familiar with every compiler?
Steve Jessop
@Artyom: C++ calling conventions are a function of C++ compilers not of processors, and most compilers allow the convention used to compile C++ to be configured. Boost is designed to be portable, so it probably shouldn't break if a user changes a compiler option.
Joe Gauterin
+8  A: 

It is clear that thread_proxy function is private internal and I do not expect that it would be mangled as "thread_proxy" because I actually do not need it mangled at all.

Regardless, it's still going to be mangled. (Had it not been extern "C") That's just how the compiler works. I agree it's conceivable a compiler could say "this doesn't necessarily need to be mangled", but the standard says nothing on it. That said, mangling doesn't come into play here, as we aren't trying to link to the function.

In fact in all my code that I had written and that runs on may platforms I never used extern "C" and this had worked as-as with normal functions.

Writing on different platforms has nothing to do with extern "C". I expect all standard C++ code to work on all platforms that have a standard C++ compliant compiler.

extern "C" has to do with interfacing with C, which pthread is a library of. Not only does it not mangle the name, it makes sure it's callable withe C calling convention. It's the calling convention that needs to be guaranteed., and because we can't assume we are running on a certain compiler, platform, or architecture, the best way to try and do that is with the functionality given to us: extern "C".

My problem is that extern "C" function pollute global name-space and they do not actually hidden as author expects.

There's nothing polluting about the above code. It's in an unnamed namespace, and not accessible outside the translation unit.

GMan
Can you give a name of any platform/compiler where C plain function calling convention is not compatible on ABI level with C++ one? Because at least on Alpha, Itanium, ARM, X86, x86_64 it is.
Artyom
@Artyom: Not on x86. It's entirely possible that your compiler uses `__cdecl` on all extern "C" functions, but `__stdcall` otherwise. `__stdcall` produces more efficient (smaller) code but does not allow creation of varadic functions because the callee cleans the stack. Since `__cdecl` is the standard in most of the C world it makes sense to require that calling convention to external code.
Billy ONeal
Mangling does not enter the picture here. Mangling is only significant when *linking* against a function by name; here its address is passed directly as a parameter to other function.
atzz
@Artyom: Who cares? If you want to argue about your specific platform, go somewhere else to do it. In *standard C++* (hint: no platform attached), you *need* to use `extern "C"` to *ensure* the behavior. That's it. Languages are an abstract concept, they aren't tied to which platforms you decide to list. That said, there are compilers/platforms today (x86, for example) that don' always use C calling conventions.
GMan
@Artyom -- x86, Borland C++ compiler. It uses fastcall by default for C++ functions.
atzz
@atzz: I'm merely listing the effects it will have. I'm make it more clear though.
GMan
Declaring the function as `extern "C"` which gives it 'C' linkage so it will be visible outside the translation unit.
Joe Gauterin
@Joe: That's incorrect. It just means "don't mangle this" and "call it like it is a C function". The unnamed namespace is like making the function static. It's *not* visible outside the translation unit. Try it yourself.
GMan
@GMan "It's not visible outside the translation unit. Try it yourself" -- it is visible, otherwise I would not find it in symbols when I run `nm -D libboost_thread.so`. So it is visible.
Artyom
@atzz -- thanks, that is what I was looking for.
Artyom
@Artyom: *"Outside the translation unit."* It is *not* globally available, and not visible outside the translation unit. Of course it exists somewhere, or you wouldn't be able to use it.
GMan
@Gman Make simple test. Create file with `namespace { extern "C" void test_c(){} void test_cpp(){} } static void test_static(){}`. Compile it as `g++ -shared -fPIC test.cpp -o libtest.so` And list all symbols with `nm -C -D libtest.so` -- you will find only one -- `test_c`... So anonymous namespace does not help.
Artyom
In C++ mangling is always an issue. It is very difficult for the compiler to know that there isn't going to be another function with the same name but different signature that gets linked in later. Plus if it didn't tell you that there was an error now but then it did when you added another function with the same name it would be confusing. C++ can break on old code because of the addition of new code but it is best to avoid it. Oh, and when you do an extern C version of a function it has to treat it different and lock down the name a little more than with C++ functions.
nategoose
@Artyom: I get no symbols. Which g++ version? Really, according to the standard the function should not be visible from outside the unit. `extern "C"` has no effect on linkage.
GMan
@GMan, are you testing this on ELF platform (Linux) or on Windows with DLLs? Because with DLLs it is different. In any case gcc-4.3.2
Artyom
+3  A: 

The question is valid - although the function is being passed to a C library, that C library is not linking to the C++ code at all. It is only given the address of the function, so it has no interest at all in the name of the function.

The point is that extern "C" is the closest thing there is to a cross-platform way of telling the compiler to make the function use the standard C calling convention on that platform (i.e. exactly how parameters and return values should be passed on the stack).

It is unfortunate that it also has the side-effect of creating an extern linker symbol at the global level. But this could be mitigated by using a name like boost_detail_thread_proxy instead.

Daniel Earwicker
I know that one of the solutions is to add "boost_` prefix to the variable and that's it. I just wondered why just not to remove `extern "C"`
Artyom
A: 

It's being used to make the function use whatever the compiler understands by the C calling convention while avoiding compiler specific keywords such as __cdecl.


That's all there is to it. It's got absolutely nothing to do with name mangling, namespaces or any of the other weird answers here (as you already knew when you asked).

Joe Gauterin