15

I saw in a cpp file that external "C" {...} encloses the definitions of several functions.

From https://isocpp.org/wiki/faq/mixing-c-and-cpp, I guess the purpose of using extern "C" in the cpp file is to make the enclosed C++ functions available to be used in a C program.

The example in the link shows that extern "C" encloses the declarations of the C++ functions only, not their definitions

Just declare the C++ function extern "C" (in your C++ code) and call it (from your C or C++ code). For example:

    // C++ code:
    extern "C" void f(int);
    void f(int i)
    {
        // ...
    }

The cpp file I mentioned at the beginning looks like instead:

    // C++ code:
    extern "C" {

    void f(int i)
    {
        // ...
    }

    void g(int i)
    {
        // ...
    }

    }

Shall extern "C" enclose the declarations or definitions of C++ functions? If so, why?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Tim
  • 1
  • 141
  • 372
  • 590
  • 1
    @Alex It doesn't really _change the ABI_, just the name mangling. – πάντα ῥεῖ Jun 20 '16 at 16:32
  • Remeber that definition is a declaration too, **[dcl.link] 7.5/6** migh be of interest. – Revolver_Ocelot Jun 20 '16 at 16:35
  • In the first case, the second function f is not using C-naming linkage. You can check this by dumping the symbol of the produced object. – xryl669 Jun 20 '16 at 16:37
  • 2
    @xryl669 If it doesn't, you have a compiler bug. – T.C. Jun 20 '16 at 16:38
  • @πάνταῥεῖ` "just the name mangling" 7.5/1 "a particular language linkage may be associated with a particular form of representing names of objects and functions with external linkage (mangling---n.m.), or with a particular calling convention (ABI---n.m.)". "Two function types with different language linkages are distinct types even if they are otherwise identical." 5.2.2 "Calling a function through an expression whose function type has a language linkage that is different from the language linkage of the function type of the called function’s definition is undefined". – n. m. could be an AI Jun 20 '16 at 18:32

5 Answers5

16

It should enclose the declarations in the header file, and definitions should be enclosed as long the translation unit is compiled using the c++ compiler, and as long the declaration wasn't seen there.
It's never wrong doing both in c++ code.

If the c compiler is used to compile the function definitions, it's not necessary (or should I better to say would be wrong syntax, see the note below).

extern "C" {} scopes control that plain c symbols linkage is used for everything inside. Otherwise c++ name mangling would be applied.


Note:

Since extern "C" {} this isn't valid c syntax, to make that working with the c compiler, you'll need to use it within #ifdef:

MyHeader.h:

 #ifdef __cplusplus
 extern "C" {
 #endif

 // ... c style function name declarations
 void foo(int i);

 #ifdef __cplusplus
 } // extern "C"
 #endif

The use of the extern "C" {} scope is actually twofold:


Exporting C++ code to C

If the above is compiled with the c compiler, it appears for it as a normal c function declaration. If compiled with the c++ compiler the extern keyword applies and the c++ name mangling will be suppressed.

Regarding the definition, the function can use any c++ features inside it's definition:

 extern "C" {
     void foo(int x) {
         std::vector v(x);
         // ... blah, more c++ stuff
     }
 }

Note that the declaration wasn't included here. This can be used as a technique, particularly useful when you want to override functions exposed from a library for weak linkage.

In case of including the MyHeader.h, the extern "C" {} scope can be omitted.


Importing C code from C++

If the above declaration is seen in the c++ compiler, again c++ name mangling is suppressed, and any call reference to foo() wil be resolved by the linker using a plain c function symbol name:

  #include "MyHeader.h"
  class MyClass {
  public:
       void bar(int y) {
           // Use foo() as plain c function:
           foo(y);
       }
  };

The foo() function implementation is provided from an object file (or archive) that was created using the c compiler.

Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Thanks. Is `#ifdef` used when calling C++ code in a C program, or when calling C code in a C++ program? – Tim Jun 20 '16 at 17:08
  • @Tim The `#ifdef` refers to the c compiler, as mentioned c doesn't understand that syntax. The uses of `extern` are either to import code compiled with the c compiler to c++, or to export code compiled with the c++ compiler to c. – πάντα ῥεῖ Jun 20 '16 at 17:11
  • Thanks. Just a somehow non-related question, is `#ifdef` recognizable by a C++ compiler? In other words, does a C++ compiler also use the directives used in a C compiler? – Tim Jun 20 '16 at 17:24
  • @Tim Sure the directive will evaluate to true ***exclusively*** in the c++ compiler. Don't confuse the c-preprocessor with the compiler language variants. – πάντα ῥεῖ Jun 20 '16 at 17:29
  • @Tim Updated the answer, I hope this clarifies all your doubts how `extern "C" {}` actually works. – πάντα ῥεῖ Jun 20 '16 at 17:41
  • "and definitions should be enclosed" citation needed. – n. m. could be an AI Jun 20 '16 at 18:09
  • @n.m. In the sub sentence: _"as long the translation unit is compiled using the c++ compiler, and as long the declaration wasn't seen there."_. No citation needed, since these need to be _self contained_. Isn't that clear? – πάντα ῥεῖ Jun 20 '16 at 18:11
  • Sorry didn't see this passage. – n. m. could be an AI Jun 20 '16 at 18:15
  • 1
    "plain c name mangling is used for everything inside" -- better to say "C language linkage", since the standard permits the calling convention to be different as well as just the name mangling. – Steve Jessop Jun 20 '16 at 18:46
  • @SteveJessop You are my escape <3. I didn't know how to name that correctly (since c doesn't provide any _name mangling_ at alll actually). – πάντα ῥεῖ Jun 20 '16 at 18:54
8

[dcl.link]/5:

Except for functions with C++ linkage, a function declaration without a linkage specification shall not precede the first linkage specification for that function. A function can be declared without a linkage specification after an explicit linkage specification has been seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.

Both versions are fine as far as the language linkage of the function is concerned. The important part is that the first declaration of the function must have extern "C" on it.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 2
    So this effectively means, if a function was declared within the `extern "C" {}` scope before, the definition will refer to this declaration regardless it was compiled as c++ or c code?` – πάντα ῥεῖ Jun 20 '16 at 16:48
3

Better should include both.

To make sure that symbol is not mangled when we link a C code in C++. we use extern "C" block.

Whenever some code is put in extern “C” block, C++ compiler ensures that the function names are unmangled i.e compiler generate a binary file with their names unchanged, as C compiler will do.

Mangling As C++ supports function overloading, so basically there can be more than one function with same name. So to distinguish between different functions when it generates object code – it changes names by adding information about arguments. Technique of adding additional information to function names is called Name Mangling.

As C does not support function overloading. So we use extern 'C' block while linking C code in C++.

µtex
  • 900
  • 5
  • 12
1

You should enclose both declarations and definitions. "C" and "C++" functions are exported with different names. To produce correct "C" external name in object file extern "C" is needed in cpp, otherwise function will be exported with C++ name mangling . You also need to enclose those extern "C" { and corresponding } into #ifdef __cplusplus and #endif in header file, which is going to be #included by a C project to avoid C compilation error

mvidelgauz
  • 2,176
  • 1
  • 16
  • 23
  • `extern "C"` is not necessary before definitions; it's only necessary before declarations. If the definition precedes the declaration (according to best practices; not an absolute requirement), the mangling will adjust to declaration. – anatolyg Jun 20 '16 at 17:07
  • @anatolyg I just recently fixed linker error in some project caused by exactly this thing - function was exported from a library with C+ name mangling and therefore could not be used in plain C project. Despite the fact that the same header (with "extern "C" ) was used for DLL compilation – mvidelgauz Jun 20 '16 at 17:12
-2

In the same document, it shows a code example that has extern "C" in the declaration, but not in the definition.

If your definition "sees" the declaration (that is, the declaration precedes the definition in the translation unit), you don't need extern "C" on the definition. But it won't hurt - it will be silently ignored by the compiler.

Here is the code example given in the FAQ:

// This is C++ code
// Declare f(int,char,float) using extern "C":
extern "C" void f(int i, char c, float x);
// ...
// Define f(int,char,float) in some C++ module:
void f(int i, char c, float x)
{
  // ...
}

If you, for any reason, decide not to include the declaration before your definition, you have to provide the extern "C" modifier:

// This is C++ code
// Define f(int,char,float) in some C++ module:
extern "C" void f(int i, char c, float x)
{
  // ...
}

However, this goes against most style guidelines of C and C++.

anatolyg
  • 26,506
  • 9
  • 60
  • 134