2

If you're tempted to flag this question as a duplicate, please note that I've read the questions on this subject, yet something still is unclear to me. I'm under the impression that this construct is used when including C headers and linking with C code (please do correct me if I'm wrong). Does it mean that I never have to use "extern C" when not dealing with object files? If I'm wrong about that, why can't the old C code just be compiled as C++, as most likely it's legal c++ code anyway?

I'm a bit iffy about it because I swear I've had situations when working with old C source code in C++ where a linker error is solved only with "extern C", and library headers do have

#ifdef __cplusplus
#extern "C"{
#endif
//......
#ifdef _cplusplus
}
#endif

around them.

EDIT: sorry for being unclear, but what I meant to ask is that whether it's true that "extern C" is only needed when including C headers and linking with pre-existing C object files? If it's true, (and it seems to be judging from comments below), why do library headers have "extern C" clauses around them, why can't they just be included and compiled as C++?

Einheri
  • 957
  • 1
  • 9
  • 22
  • 1
    "Why can't the old C code just be compiled as C++?" Even if the C code is valid C++, `extern C` is meant for linking against object files compiled as C, which means you still need to use the C-based calling convention. – Chris Hayes Dec 23 '13 at 06:23
  • @ChrisHayes so it's true when I'm not working with pre-existing object files, I don't need "extern C"? – Einheri Dec 23 '13 at 06:38
  • Just to make it explicit (I still see a close vote): The other questions cover the subject "Is `extern "C"` needed **if** linking to C code", this question is "Is `extern "C"` needed **if and only if** linking to C code". Please focus on the **only if**. – MSalters Dec 23 '13 at 07:57

4 Answers4

5

Name mangling rules are different for C. And C can have a different ABI than C++. These reasons alone require you to use extern "C" when embedding C code in C++ code. Even if a compiler can compile both C and C++ code, it might use different name mangling rules or ABIs for the two languages.

Also, your assertion that "[C code is] most likely ... legal c++ code" is not quite true, as C and C++ have diverged more and more as the years have gone on. They have a lot of similarities, but they also have a good number of differences.

Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • sorry for being ambiguous. Please refer to the edit above, thanks – Einheri Dec 23 '13 at 06:43
  • Also note that different C++ compilers and in the past even different versions of the same compiler have used different name mangling conventions. So its quite common for a C++ program to define its functions as "extrn" so that it usable by a calling program using a different C++ compiler. – James Anderson Dec 23 '13 at 06:44
  • 1
    @user3109672: Updated. Even if the same compiler compiles C code and C++ code, it might do it differently (it might have two modes, a "C mode" and a "C++ mode" that it switches between, with each mode having different rules). – Cornstalks Dec 23 '13 at 06:57
  • @JamesAnderson's comment is particularly important in the context of creating a plug-in interface for a C/C++ application (e.g. where you allow dynamic loading of shared libraries via `dlopen` or `LoadLibraryEx`). If you choose C++ linkage then plug-ins will likely fail at runtime when you upgrade your compiler due to C++ ABI changes. If you choose C linkage, then plug-ins will likely continue running, as the C ABI is far more stable w.r.t. compiler changes. So to prevent plug-in users/writers from needing recompiled plug-ins for a changed C++ ABI, C linkage is often a good call. – Rob Dec 23 '13 at 07:58
  • I should also mention that [C doesn't have a standard ABI](http://stackoverflow.com/questions/4489012/does-c-have-a-standard-abi), but in practice the ABI it does provide changes far less frequently than C++. – Rob Dec 23 '13 at 07:59
1

The library itself is a C object file, therefore in order to use it your application has to expect a C-ABI for calling the functions in the library and you need to provide the appropriate hint to the compiler when you prototype the functions.

extern void libraryFunc();

If the library is actually compiled as C, which is the only way it can support C and C++, then you need to include annotation for C++ compilers that this MUST be linked as C.

#ifdef __cplusplus // only true when compiling with a C++ compiler
extern "C" {
#endif
extern void libraryFunc();
#ifdef __cplusplus
}
#endif

To a C compiler, this reads

extern void libraryFunc();

To a C++ compiler, this reads

extern "C" {
extern void libraryFunc();
...
}

which is equivalent to

extern "C" void libraryFunc();

If the duplication of extern bothers you, consider:

#if defined __cplusplus
# define C_EXTERN extern "C"
#else
# define C_EXTERN extern
#endif

EXTERN_C {
  void foo();
}

The compiler and linker now know to use the C ABI when trying to call/link that function.

Note that the C++ ABI is a superset of the C ABI (application binary interface) so if you want to share code, C is the LCD and needs to be your common interface. C is completely unaware of C++ "name mangling" etc.

kfsone
  • 23,617
  • 2
  • 42
  • 74
0

This is essentially answered here: When to use extern "C" in simple words?

But the pertinent point is that, when compiling in C++, the names of functions are "mangled" to encode certain information about the function (like argument types). Since C++ always mangles a function name the same way, everything is consistent between the mangled name call and what is put in the object file.

If you compile a file in C called "foo", and in your C++ file you have extern foo(int c);, the C++ compile will have mangled "foo" into something different, for example, foo__Ic (I just made it up, the actual mangling will look different).

Meanwhile, in the plain C code compiled with the C compiler, the object code has defined symbol that is simply foo.

However, when the whole thing is linked, the C++ code has an external symbol foo__Ic that it's trying to resolve, which does not match the defined symbol foo in the C object file.

Hope that helps.

Community
  • 1
  • 1
Eric
  • 843
  • 6
  • 15
0

There's another case not mentioned yet. extern "C" specifies the C linkage, but C is not the only other language. C linkage is also used by other languages which are too obscure to have their own widely accepted linkage. E.g. Java uses C linkage, too. Obviously you can't compile that Java code with C++, so you do need extern "C" on the C++ side.

MSalters
  • 173,980
  • 10
  • 155
  • 350