I am very curious about what happens during linking, and, during my research in this area I have stabbed upon this code
#ifdef __cplusplus
extern “C” {
#endif
extern double reciprocal (int i);
#ifdef __cplusplus
}
#endif
The code was in some header file, which was include by .c and .cpp source files of one program. It's a declaration of a function, which is then defined in .cpp file. Why does it work? I mean, during the compilation of the .cpp file this will turn into
extern "C" {
extern double reciprocal (int i);
}
The outer extern both makes the function visible in the global scope and converts the C++ style of function names into C one. But there also is an inner extern. Is it OK the function is externed twice?
The c++ language is allergic to adding new keywords so some get reused to mean different things. extern is one of these re-used keywords. It has 3 possible meanings:
external linkage - the variable or function is defined somewhere else
language linkage - the variable or function is defined in an "external" language
explicit template instantiation declaration
In your case you are using 1 and 2. extern "C" declares that the code has "C" rather than the default "C++" linkage. This also implies external linkage so in pure C++ code you can just write:
extern "C" {
double reciprocal (int i);
}
and reciprocal will be automatically be marked extern. Adding an extra extern has no effect and is required for the C version which doesn't have the extern "C" wrapper.
Note that if you are using single declaration version of extern "C" then using a second extern is not valid:
extern "C" extern double reciprocal (int i);
As the second extern is not required the correct declaration is:
extern "C" double reciprocal (int i);
Related
This question already has answers here:
Is extern "C" required also for linking global variables used in Cpp file to the one defined in a cfile?
(2 answers)
Closed 7 years ago.
I am using Visual Studio 2013. I have a global variable declared in a C source file (file1.c) and used in a method defined in a C++ source file (file2.cpp). A header included from both files declares the variable as extern. The project property C\C++ -> Advanced -> compile as is set to defualt, which according to the documentation means the compiler uses the file extension to infer file type. This setup results in an unresolved external symbol linking error. If I set this option to either Compile as C code or Compile as C++ code, the project compiles and link without an error. I fail to understand this behavior. (Btw, under linux/GCC the code compiles OK).
Here's a minimal example reproducing the problem:
// file1.h
extern int g_i;
// file1.c
#include "file1.h"
#include "file2.h"
int g_i;
int main() {
g_i = 1;
foo();
return 0;
}
// file2.h
#ifdef __cplusplus
extern "C"
#endif
void foo();
// file2.cpp
#include "file1.h"
#include "file2.h"
void foo() {
int i = g_i;
}
Language linkage applies to variables as well as functions. In the C file you define a variable g_i which obviously will have C language linkage (from the point of view of a C++ compiler). In the CPP file (or at least the header file) you need to declare the variable as having C language linkage. So what you need is:
// file1.h
#ifdef __cplusplus
extern "C"
#endif
extern int g_i;
Alternatively, assuming that the real code has more than one variable in the header file, you may prefer:
// file1.h
#ifdef __cplusplus
extern "C" {
#endif
extern int g_i;
... // More declarations to taste
#ifdef __cplusplus
}
#endif
GCC obviously doesn't distinguish between C and C++ linkage for variables (which is perfectly allowable).
If you force everything to be compiled as C or if you force everything to be compiled as C++, then of course the definition of the variable and the usage of the variable are defaulting to the same language linkage - so it just works.
See http://en.cppreference.com/w/cpp/language/language_linkage for details. In particular
... every variable name with external linkage, has a property called
language linkage.
I have an int ID, which I want to define in C++ and make available for C linkage (contrived case for the sake of simplicity):
/* i.h */
#ifdef __cplusplus
extern "C" {
#endif
extern int ID;
#ifdef __cplusplus
}
#endif
Here's a C and a C++ program using the int:
/* m.cpp */
#include "i.h"
#include <iostream>
int main() { std::cout << ID << std::endl; }
/* m.c */
#include "i.h"
#include <stdio.h>
int main() { printf("%d\n", ID); }
Now what I'm wondering is the syntax of extern "C" and/or extern. Here's how int ID can and cannot be defined:
/* i.cpp */
// const int ID = 88; // no C linkage, obviously, LNK2019/1120
// extern "C" const int ID = 88; // provides C linkage
// extern "C" { const int ID = 88; } // no C linkage, surprisingly, LNK2019/1120
// extern "C" { extern const int ID = 88; } // C linkage restored
Compiling:
cl /nologo /W4 m.cpp i.cpp /MD /EHsc
cl /nologo /W4 m.c i.cpp /MD
What I don't understand is the syntax when extern "C" is used with a {block}. I have to repeat the extern, whereas with the blockless form of extern "C" I do not. Is this just a syntax quirk or is there more to it?
I stumbled upon this issue on page 98 of Inside COM by Dale Rogerson. There is a code listing with the nested extern and a comment intended to clarify (but which I don't understand):
#include <objbase.h>
extern "C"{
extern const IID IID_IX = {0x32bb8320, 0x41b, 0x11cf, ...};
// The extern is required to allocate memory for C++ constants.
}
Can anyone explain the internal extern?
The inner extern means what expected: "the symbol is defined somewhere else, it has external linkage, don't allocate space for it in this unit (unless defined here as well)".
The outer extern "C" { ... } has maybe a bit misleading syntax, it only tells the compiler "if you are creating names of any symbols with external linkage inside this block, use traditional C naming (C language linkage) instead of C++ name mangling (C++ language linkage) for them". But it does not specify that all things inside the block are "defined somewhere else" (have external linkage) -- they are still declared with the default internal linkage. That's why you need the inner extern as well.
The one-line variant extern "C" <variable declaration> is just a shorthand, as you probably want to define an external variable if you care about its cross-unit symbol name.
(As a side-note, I would include i.h also in i.cpp, that way I wouldn't have to remember to mess with extern "C" any more in the implementation.)
The problem is that const and extern are warring with each other. const means (among other things), "Make this definition internal, unless there's an explicit extern on it.". When the definition is in an extern "C" block, there's no extern directly on the definition, so the "implicit internal" from the const takes precedence. The other definitions all have an extern directly on the definition, so it becomes external.
Here's how int ID can and cannot be defined:
Careful! extern "C" has different effects in different contexts.
N3797 §7.5/7:
A declaration directly contained in a linkage-specification is treated
as if it contains the extern specifier (7.1.1) for the purpose of
determining the linkage of the declared name and whether it is a
definition. Such a declaration shall not specify a storage class.
extern "C" int i; // declaration
extern "C" {
int i; // definition
}
So the second line in your snippet is just a declaration whilst your third line is also a definition. This changes what effect the linkage-specification has on the declarations - you can't give a name defined in a C++ translation unit C linkage. You have to make it a pure declaration.
When I build source, it throws an error: declaration of 'globalMemTrace' has a different language linkage
#ifdef MEMDEBUG_SIMULATIONS
#include "mem-trace.h"
MemTrace *globalMemTrace;
#endif
// omitted unrelated parts
int Tcl_AppInit(Tcl_Interp *interp)
{
#ifdef MEMDEBUG_SIMULATIONS
extern MemTrace *globalMemTrace;
globalMemTrace = new MemTrace;
#endif
}
I've googled several times for it. Some said that it is due to a bug if clang and some said tricks in using extern differently may solve it.
But since I am not such a profession, I've tried some of them and failed to solve it. Is there any nice way to deal with it?
It's written in C++ and the problem occurs at extern MemTrace *globalMemTrace;
C++ offers linkage between C++ and non-C++ languages in the from of language linkage.
For example
// in C++ program
extern "C" int displayfoo(const char *);
int main() {
return displayfoo("hello");
}
/* in C program */
#include <stdio.h>
extern int displayfoo(const char * str) {
while (*str) {
putchar(*str);
putchar(' ');
++str;
}
putchar('\n');
}
You are using a C function displayfoo from c++ code, So you need to tell the compiler/linker that it is from different language. That is done by extern "C".
In your code MemTrace *globalMemTrace; may be declared previously in a C code or a C block inside c++, So you need to declare it like
extern "C" MemTrace *globalMemTrace;
It means that the actual variable was declared in C code, or at least wrapped in an extern "C" block in C++ code, but the extern is declared in C++ code, thus it cannot link to the variable as they exist in different languages.
Have a look at these articles:
Language linkage
Linking C and C++ code
It seems that this name is already declared as having C language linkage.
extern "C" MemTrace *globalMemTrace;
I want to use some c++ classes in shared library with C linkage. And i got following problems.
If
#include <iostream>
extern "C"
{
void f(){}
}
Compiles and links succesfully, but f() could not be found in resulting library.
If
extern "C"
{
#include <iostream>
void f(){}
}
I got many compiler errors (just dont know how to correctly translate them in english, something about template with C linkage) on every occurence of C++ keyword "template" in iostream and included headers.
What should be done?
The first variant is correct. Only stuff that even exists in C can be declared in a extern "C" block, and templates and classes certainly don't belong in that category. You only have to make sure, that your function is also declared as extern "C" in the header if you are using a C++-compiler. This is often achieved by writing
#ifdef __cplusplus
// C++ declarations (for example classes or functions that have C++ objects
// as parameters)
extern "C"
{
#endif
// C declarations (for example your function f)
#ifdef __cplusplus
}
#endif
in the header.
The first is correct; system headers (and most other headers as well)
can only be included at global scope, outside any namespaces, classes,
functions or linkage specification blocks. There are likely things in
<iostream> that wouldn't be legal in an extern "C", and even if
there weren't, the name mangling for extern "C" is almost certainly
different from that of C++, and the library itself was surely compiled
as extern "C++".
How did you define f? This could be a similar problem: if the source
file compiles it as an extern "C++" function, then the name will be
mangled differently than it was in the client files which compiled it as
an extern "C" function.
The general policy here is to handle the headers and the function
definitions/declarations in the same way you normally do, except that
you ensure that the header can be included in both C and C++ sources,
e.g.:
#if __cplusplus
extern "C" {
#endif
void f();
// Other `extern "C"` functions...
#if __cplusplus
}
#endif
Then include this header in all files where the function f() is used,
and in the file where it is defined.
Use __declspec to export functions, classes, etc...
Also: http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx
And this one is very good: http://www.flounder.com/ultimateheaderfile.htm
I am trying to interface to Ada in C++ using externs. What is the difference between these two implementations?
Implementation A
namespace Ada
{
extern "C"
{
int getNumber();
int index;
int value;
}
}
Implementation B
namespace Ada
{
extern "C"
{
int getNumber();
}
extern "C" int index;
extern "C" int value;
}
Both implementations compile just fine. But Impl-A fails to link, I get a multiple definition error for index and value. I'm just trying to understand the differences.
extern "C" only conveys the linking conventions to use for the code within the extern "C" block. Anything in that block will be linked against as if it were pure c. Confusingly, extern int is totally different. It means that you promise there is an actual int named index and an actual int named value somewhere, but they cannot be found here. In your implementation-A the ints are actually not extern in the second sense - the extern "C" only implies that they provide a strict c linking convention.
Same keyword but totally different uses, which is unfortunate since it leads to weird issues like this. Mixing them is legal (obviously), but they don't behave together the way that their name implies.
EDIT
See Charle's response for the true definition of the extern weirdness as defined in the C++ standard.
A linkage-specifier (i.e. extern "C" or extern "C++") applied to a brace enclosed sequence of declarations has no effect on whether the enclosed declarations are definitions or not, however a linkage-specifier applied to a single declaration is treated as an extern specifier for the purposes of determining whether a declaration is also a definition. (7.5 para 7 of C++03)
So:
extern "C" { int a; } // a is declared and defined
extern "C" int a; // a is just a declaration (as if extern int a;)
extern "C" int a = 0; // a is a definition because of the initializer.
I'm not sure why the second works, but you want
namespace Ada
{
extern "C"
{
int getNumber();
extern int index;
extern int value;
}
}
because you only want to declare index and value, not define them. (See this answer for the difference.)