C++ Extern / Multiple Definitions - c++

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.)

Related

Extern used twice in C++

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

How to declare an extern C function inside a function in C++?

I have an inline function, roughly like this:
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
This is a simplification: my functions do have parameters and return values.
However, I want this header to work in both C and C++ files. Currently, linking fails because C++ files attempt to find an implementation of SomeOtherFunction with C++ linkage. I thought I could just fix this by using extern "C":
inline void SomeFunction() {
#ifdef __cplusplus
extern "C" void SomeOtherFunction();
#else
extern void SomeOtherFunction();
#endif
SomeOtherFunction();
}
This causes Clang to fail with:
error: expected unqualified-id
extern "C" void SomeOtherFunction();
^
How can I do this correctly?
extern "C" is a linkage-specification. C++ standard section 7.5 Linkage specifications paragraph 4 states that:
A linkage-specification shall occur only in namespace scope (3.3).
E.g. you can say extern "C" in global namespace or some specific namespace. Outside of namespaces it is illegal.
Function declarations are possible though in smaller scopes. If you remove linkage specification your code will compile (but not link):
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
If you really need SomeOtherFunction declaration in a smaller scope (e.g. hide from global scope) you can put your declaration into a header file to a dedicated scope and then use in your function:
Header:
namespace other {
extern "C" void SomeOtherFunction();
}//namespace other
Code:
void SomeFunction()
{
other::SomeOtherFunction();
}
Credit goes to these two answers on stackoverflow: here and here.
From the C++11 standard (in [dcl.link], emphasis mine):
4 Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope.
(linkage-specification refers to extern string-literal ..., i.e. extern "C" in your case.)
This means you can't have extern "C" inside of a class or function.
What's the point of declaring SomeOtherFunction inside of SomeFunction? It still has to be a global symbol and visible to the linker.
So why not do this?
#ifdef __cplusplus
extern "C"
#endif
void SomeOtherFunction();
inline void SomeFunction() {
SomeOtherFunction();
}
The following also seems to work:
extern "C" {
inline void SomeFunction() {
extern void SomeOtherFunction();
SomeOtherFunction();
}
}
But it would have the side effect of making SomeFunction also use C linkage (which is hopefully OK as (per your requirements) it needs to be usable from C, too).
You can do this like that. I assume you have a header file, a C source and a C++ source.
Header file:
inline void SomeFunction()
{
void SomeOtherFunction_Bridge();
SomeOtherFunction_Bridge();
}
C++ source:
extern "C"
{
void SomeOtherFunction();
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
C source:
void SomeOtherFunction()
{
// Function with a code doing something
}
void SomeOtherFunction_Bridge()
{
SomeOtherFunction();
}
Checked on GCC, it compiles.
extern tells the compiler that a symbol (function, variable) is defined in some other module. When this module (C++ file) is compiled, object file contains a list of external symbols it needs. So this is on a level of a C++ file, it cannot be in smaller scope (function, block).

What if using extern declaration inside the function?

I've tried the following code and got an error.
int main()
{
//this will cause redefinition error
extern int x;
int x=2;
}
I've seen some answers about extern such as
When to use extern in C++
Defining extern variable in main() vs. globally
and got an concept,but I am still wondering what does the compiler do in this case. Can extern be used(legal) inside some function?
update:
More specifically, since extern int x is just a declaration,why can't I define int x? Does the compiler take extern int x as a definition?
but I am still wondering what does the compiler do in this case. Can extern be used(legal) inside some function?
it can, but you must not redeclare variable as you have in your code. So this is a valid example:
int main()
{
//this will cause redefinition error
extern int x;
x=2;
}
int x;
Of course it can be used, don't define another x inside the function:
int main()
{
extern int x;
x=2;
}
As the others have answered, yes, you can use it in your function as long as you don't declare another variable with that name.
To your question of what the compiler does, dreamlax's answer to the question you linked, handles it pretty well. The compiler doesn't need to do/know anything other than what it's type is so that it knows how it can be used. The linker will see that it's an extern and know that it needs to go find where it is actually declared.
This MSDN link provides more general info on externs and what Microsoft does in VS 2015.

External linkage and »extern "C"« block

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.

declaration of 'x' has a different language linkage

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;