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.
Related
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);
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).
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 am creating a C++ library with a C-ABI interface.
This is how GCC treats the extern "C" qualifier with regards to mangling:
namespace x {
extern "C" int monkey(int x) {
return 1;
}
int chimpanzee(int x) {
return 1;
}
}
The relevant nm output:
00000000004005cd T _ZN1x10chimpanzeeEi
00000000004005bf T monkey
Question:
I want to leave functions which are involved in the C-ABI inside a namespace, for maximum flexibility for reuse. Important Note: Once the library has been compiled I will give the linker a map file (GCC) or a module definition file (MSVC).
Is the mangling output standard behaviour -- will other major compilers (MSVC in specific) strip mangling as well ?
are their any pitfalls or best-practises regarding placing functions in a name-space when they are involved in an external ABI?
Will this interfere with the C-ABI export of the de-mangled functions during link time ?
What you're doing is fine and will give you the effects that you want. From The C++ Programming Language, 3rd Edition, page 208: "A name with C linkage can be declared in a namespace. The namespace will affect the way the name is accessed in a C++ program, but not the way a linker sees it. The printf() from std is a typical example. … Even when called with std::printf(), it is still the same old C printf()."
This is for MSVC.
The namespace itself is not name-mangled, but the name of the namespace is incorporated in to the function's (or object's) name when name mangling occurs. This process is undocumented, but described here.
Answering your specific questions by jumping around:
1) There is no Standard-defined behavior regarding name mangling. What the Standard actually says is that implementations provides a C-compatible linkage for extern "C" constructs:
7.5.3 [Linkage specifications]
Every implementation shall provide for
linkage to functions written in the C
programming language, "C", and linkage
to C + + functions, "C++". [Example:
complex sqrt(complex); // C + + linkage by default
extern "C" { double sqrt(double); // C linkage }
—end example]
Ultimately what this means is that since C has no concept of namespaces, if extern "C" functions or objects in namespaces, your exported names will lose the namespace qualification. This leads to...
3) Yes, you can have a linkage problem. Try this:
main.h
#ifndef MAIN_API
# define MAIN_API __declspec(dllexport)
#endif
namespace x
{
extern "C" MAIN_API void foo();
};
namespace y
{
extern "C" MAIN_API void foo();
};
main.cpp
#include <cstdlib>
#include <iostream>
using namespace std;
#define MAIN_API __declspec(dllexport)
#include "main.h"
void x::foo()
{
cout << "x::foo()\n";
}
void y::foo()
{
cout << "y::foo()\n";
}
int main()
{
}
This will emit a linker error because the extern "C"-ed versions of x::foo() and y::foo() have lost their namespace identification, so they end up with exactly the same name: foo()
2) Best practices regarding this. If you must export a C-ABI for functions in namespaces, you have to be careful that the names you end up exporting are not the same. To some degree, this defeats the purpose of using a namespace in the first place. But you can do something like this:
#ifndef MAIN_API
# define MAIN_API __declspec(dllexport)
#endif
namespace x
{
extern "C" MAIN_API void x_foo();
};
namespace y
{
extern "C" MAIN_API void y_foo();
};
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.)