What is the Effect of Declaring 'extern “C”

2020-06-17 06:35发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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.



回答4:

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


回答5:

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.