10

I'm writing a C++ shared library for a C program to use. However, I have a question about extern and extern "C".

Consider the following code

My header file is like this:

#ifdef __cplusplus      
     extern "C" int global;
     extern "C" int addnumbers(int a, int b); 
 #else
      extern int global;
 #endif

This works perfectly fine; I just have to declare

int global;

in either my .cpp or my .c file. However, what I don't understand is:

What is the difference between extern "C" and extern here? I tried commenting out extern "C" int global and it works! Why?

I know that extern "C" is used for making C linkage. That's why I have extern "C" int addnumbers(int,int). In other words, if I want to write a C++ function that is to be used in a C program, I write extern "C". Now, what about global variables - the situation is different here I guess? I want the C program to use a C++ variable named global, but I can use extern not extern "C". Why is that? This is not intuitive to me.

Comment: I don't think this is a duplicate, because I'm asking what the difference is when you use it for variables versus functions.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
Thenewstockton
  • 443
  • 6
  • 18
  • 2
    I don't think this is a duplicate, because I'm asking what the difference is when you use it for variables versus functions. – Thenewstockton Jul 01 '16 at 09:18
  • I invite you to make that much clearer in your question. – Lightness Races in Orbit Jul 01 '16 at 10:14
  • Although I'm struggling to detect the difference between _what is the difference between `extern "C"` and `extern`_ and _what is the difference between `extern "C"` and `extern` for variables_. Perhaps the question is _is `extern "C"` different when used on functions vs variables?_ and the answer is simply "no" – Lightness Races in Orbit Jul 01 '16 at 10:16
  • 2
    you will not see difference between extern "C" and extern for variable because compiler does nothing with variable name. it influences only on function name. – AnatolyS Jul 01 '16 at 10:19
  • http://stackoverflow.com/a/1041880/6464825 –  Jul 01 '16 at 10:23
  • FWIW, a library that exposes global variables is not a great idea. – Oliver Charlesworth Jul 01 '16 at 10:59
  • @AnatolyS Can you elaborate on extern variables being not applicable? The link provided by AnandS seems to mention the opposite. – mgouin Jan 24 '19 at 22:51

4 Answers4

19

By attaching extern "C" to your C++ declarations (objects and functions alike) you give them "C linkage" - make them accessible from C code. If you omit this "language linkage" specification, the compiler doesn't do any effort to do proper linkage. In the case of functions, this results in failed linkage, because of mangling. In the case of global variables, everything might work fine, because variables don't need mangling.

However, on my system (MS Visual Studio), linkage between C and C++ doesn't work if I "forget" to specify the extern "C" linkage specification in the C++ header file. Example error message:

error LNK2001: unresolved external symbol "int global" (?_global)

While, when I examine a compiled C++ source code that contains the definition of global with the dumpbin utility, I see

00B 00000014 SECT4  notype       External     | ?global@@3HA (int global)

So MS Visual Studio mangles the names of global variables, unless they have C linkage - this makes C linkage specifications mandatory.


In addition, consider the following example:

namespace example {
    int global;
}

If the global variable is inside a namespace, C code will not get access to it. In this case, all compilers will require the proper linkage specification on the C++ declaration:

namespace example {
    extern "C" int global;
}

Conclusion:

Use extern "C" when you want C linkage - doesn't matter if it's a function or a global variable. If it's a global variable, it may work regardless, but it's not guaranteed (and may be dangerous).

anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • Great answer and insight about mangling of global and namespace-scoped variables! – Gabriel Staples Mar 23 '18 at 00:12
  • What if I have a variable that is declared in the C++ file and I want it to have C linkage? I cannot make it "extern "C"" because doing so would make it "extern" when it is in fact defined locally. It is a global variable but is defined in the C++ file. – Yan King Yin Mar 26 '20 at 05:29
  • Short answer: `extern "C"` doesn't imply `extern`. But you should definitely use the "Ask Question" button to get a proper answer for that. – anatolyg Mar 26 '20 at 07:43
2

extern simply tells the compiler that the next variable(global) may not have been declared yet, but it is declared as global in a different translation unit, and during the linking stage the symbol "global" will be associated with an area in the memory.

while extern "C" is, as a few people commented, is used to solve the issue of name mangling in C++, this function will be known as addnumbers_i_i (or something similar) by the linker, while in c its symbol is addnumbers

Vasfed
  • 18,013
  • 10
  • 47
  • 53
monkeyStix
  • 620
  • 5
  • 10
  • 2
    Actually, `extern` is put at a **declaration** of a variable to indicate that it is **defined** elsewhere to avoid **defining** a new variable (of the same name as another one) which may cause the linker to fail and is just not what you need when you want to share a single global variable. – JimmyB Dec 11 '18 at 20:12
0

"C++ has a special keyword to declare a function with C bindings: extern "C". A function declared as extern "C" uses the function name as symbol name, just as a C function. For that reason, only non-member functions can be declared as extern "C", and they cannot be overloaded."

There is no standard in C++ for function names generated by compiler. Keyword extern "C" instructs compiler to generate function name in C standard.

Beka
  • 97
  • 5
0

I find that extern "C" is used to make the C++ function compiled in C standard and it don't do with variables, for the solutions of function name in C and C++ are different. Such as "void foo( int x, int y )", C compiler will translate it into "_foo", while C++ compiler will translate it into "_foo_int_int".