views:

136

answers:

5

Based on this question I understand the purpose of the construct in linking C libraries with C++ code. Now suppose the following:

I have a '.so' shared library compiled with a C++ compiler. The header has a 'typedef stuct' and a number of function declarations. If the header includes the extern "C" declaration...

#ifdef __cplusplus
extern "C"
{
#endif

  // typedef struct ...;
  // function decls

#ifdef __cplusplus
}
#endif

... what is the effect? Specifically I'm wondering if there are any detrimental side effects of that declaration since the shared library is compiled as C++, not C.

Is there any reason to have the extern "C" declaration in this case?

+3  A: 

When compiling C++ the method name changes (mangling) - and you won't be able to call that method from another dll/exe that uses C.

In order to keep the class and method name you need to compile them as "C" without name mangling.

The library is still a C++ library but it exposes some of its declarations (the one in the extern "c" block) as C methods.

Dror Helper
+2  A: 

The #ifdef guarded extern declaration is to tell C linkers that the symbols have C (unmangled) symbol table entries. The #ifdef ensures that there is no effect in the code unit (file) compiled by a C compiler.

msw
+7  A: 

This is important so that the compiler doesn't name mangle. C++ uses name mangling to differentiate functions with operator overloads.

Run "/usr/bin/nm" against a binary to see what C++ does with your function names: _ZSt8_DestroyIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEiEvT_S7_SaIT0_E

extern "C" prevents that name mangling.

IIRC, that makes it possible for program to dynamically link in symbols at run time. It's common for "plugin" type architectures.

Stephen
Thanks for the info. I was thinking of it from perspective the client including the header, and not the library exporting the names.
Adam
A: 

One detriment to using extern "C" for a C++ API is that it prevents you from having function overloads:

extern "C"
{
    // ILLEGAL - C linkage does not support function overloading
    void foo(int x);
    void foo(const char *str);
}
R Samuel Klatchko
The point of using `extern "C"` is for both C and C++ code to share an API, and C is the lowest common denominator, so you have to abide by the rules that the C compiler enforces. If it *were* a C++ API, then you wouldn't use `extern "C"` and only compile with a C++ compiler and everything would be fine.
quamrana
@quamrana - and his question is "what is the effect to a C++ shared library". It's unclear from the question if he needs to be able to call his library from C code.
R Samuel Klatchko
A: 

The #ifdef in the example means that only a C++ compiler will see the extern wrapping the header file which will mean that it will produce non-mangled names. A C compiler doesn't see the extern (which it wouldn't understand), but always produces non-mangled names.

This means that both C and C++ compilers will produce the same symbols in their object files, so whichever compiler produces object code for the declared functions, all the object files will successfully link because symbols have the same linkage and the same name.

There should be no implications for either statically linking, or linking with a shared library.

quamrana