extern "C" static void* function - c++

After reading about extern and static, I am confused to come across the code which has the line below:
extern "C" static void* foo(int* a){
return foo1(a);
}
Why does this not generate any error?

The following also compiles and does the same thing as your line:
extern "C" {
static void* foo(int* a){
return foo1(a);
}
}
The static means that foo() will only be available in file scope, and it overrides the extern "C" when it comes to linkage. Normally, extern "C" effects the name of the function used by the linker if/when it is exported, so that the function could be called from other object files when the entire program is linked. Usually, this is used when either you want to link to an object file built from C source where foo() was defined, or where you want to define foo() so that C code can call it. However, the static causes foo to simply not be exported at all, so it basically doesn't even get a name (it has internal, not external linkage).
extern "C" also has a secondary effect. It also becomes part of the type of foo. That is, C++ code will see foo as having type extern "C" void(int*). Basically, this controls calling convention. A C++ compiler may e.g. arrange arguments differently in registers/on the stack than a C compiler might. Making foo be a C function means that it will use the C conventions and not the C++ conventions. This makes it safe to e.g. pass a function pointer to foo to a C function that expects a pointer to a C function. For example, the standard library has
extern "C" typedef int C_CMP(void const*, void const*);
extern "C++" typedef int CXX_CMP(void const*, void const*);
void std::qsort(void *, std::size_t, std::size_t, C_CMP);
void std::qsort(void *, std::size_t, std::size_t, CXX_CMP);
With the extern "C", &foo is passed to the first overload, but without it/with extern "C++", it is passed to the second. It would not be safe to declare foo without extern "C" and then try to pass it into a C function that expects a pointer to a C function. It would probably work, but it might also break horribly. Add the extern "C" and it becomes correct—you're safe.

Related

Calling mangled class instance methods from function marked extern C

I have a typically declared class:
class Task {
public:
int test(int &c);
};
int Task::test(int &c) {
c += 8;
return c;
}
For compiling to WASM, I was trying to instantiate this class and call the test method, like so:
extern "C" {
Task t;
int scratch() {
int c = 123;
t.test(c);
return c;
}
}
with extern "C" directive to prevent name mangling that makes exposing it difficult on the JS module.
However, compiling this program gives error undefined symbol: _ZN4Task4testERi (referenced by top-level compiled C/C++ code), indicating that the "unmangled" int scratch() method cannot call the "mangled" int Task::test(int &c). Wrapping the class definition and implementation with extern "C" produces the same output.
How could I best call int Task::test(int &c) on an instance from a function that is marked extern "C"?
Mangling is close to a hack that was invented to allow the low level linker to make a difference between int foo(int) and int foo(void). You can use extern "C" to explicitely forbid mangling, but you declare symbols to have that linkage, so it should only be used for plain functions and not for classes nor class members.
The idiomatic way is to remember that a call to a non static member function carries a hidden this pointer. So you do not change anything to the Task class but declare a plain function to act as a relay:
extern "C" {
int task_test(Task *obj, int *c) { // C language does not know about reference hence a pointer
return obj->test(*c);
}

Why we should Extern "C" a struct? [duplicate]

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

extern and extern "C" for variables

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

static member function with C language binding?

The following C++ code compiles with Visual C++ and g++:
struct S
{
static void foo();
};
extern "C"
void S::foo() {}
struct T
{
static void foo();
};
extern "C"
void T::foo() {}
auto main() -> int
{
S().foo();
T().foo();
}
Is it valid?
If it's valid, since the implementation may be in a separate translation unit, does that imply that a static member function always has the same calling convention as a C function (and if not, how does it not imply that)?
C++11 7.5/4 "Linkage specifications"
A C language linkage is ignored in determining the language linkage of
the names of class members and the function type of class member
functions.
So your example is valid in the sense that it's not malformed or an error, but the extern "C" should have no effect on S::foo() or T::foo().
A static member function has the same calling convention as a C function. But, name mangling applies. So, even if you get away with declaring your static member as extern "C", the linker would probably not find it when you try to link it against the C code that calls that function.
What you can easily do is declare a wrapper/stub that calls the static member from a plain function. Also, you can assign the static member function's address to a plain function pointer.
No it is ignored, the problem is name mangling (function naming for linkage phase). So the trick is to define a C function and use your C++ static method as a stub to call it, like this:
struct S
{
static void foo();
};
extern "C" void S_foo_impl();
void S::foo() { S_foo_impl(); }
auto main() -> int
{
S::foo();
}
Of course, S_foo_impl should be defined in a external C module.

What is "extern linkage and with C language linkage"

What does the author mean about "extern linkage" and "C language linkage" in the following paragraph, extracted from [1].
"There are two different forms of the extern C declaration: extern C as used above, and extern C { … } with the declarations between the braces. The first (inline) form is a declaration with extern linkage and with C language linkage; the second only affects language linkage. The following two declarations are thus equivalent:"
Can you further elaborate what he's trying to explain with this example?
[1] http://tldp.org/HOWTO/C++-dlopen/thesolution.html
What the author is saying relates to these two lines:
extern "C" int foo;
extern "C" { int bar; }
foo is a variable declared but not defined. It exists elsewhere. On the other hand, bar is both declared and defined.
Think of a declaration as just stating that something exists somewhere but not actually creating it. Definition is therefore declaration plus bringing that thing into existence.
The latter one is exactly the same as int bar; but will "publish" the variable with C linkage. For example, a function int max (int a, int b); may be published as _max in C language linkage and _max$$int$int in C++ language linkage (to allow more than one function with the same name).
Note that "publishing" in this context is how the function looks to the linker, so that your code can link to it. Without C language linkage, it's usually rather difficult to link C code with C++ libraries.
Clumsy wording, yeah. What he's trying to get at is,
extern "C" int foo();
is the same as
extern "C" { extern int foo(); }
but not the same as
extern "C" { int foo(); }
... except that there is no practical difference between "extern int foo();" and "int foo();" at file scope in C++, so you are entirely forgiven for scratching your head. Here's a case where it actually makes a difference:
extern "C" const int x = 12;
extern "C" { const int y = 12; }
x will be visible outside the translation unit, y won't.