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.
Related
I have a DLL in pure C code. I would like to find a way to remove the library name prefix from the functions, classes, and structs; EX:
// lib.h
void foobar();
// lib.hpp
namespace foo {
bar();
}
I would like to avoid simply writing a wrapper for every function, since I'd have to write it for every time I want to add a function. Is there a better / more efficient way of writing this?
I started writing the wrapper idea, but there's a lot of functions to write this for. Void pointers worked a little better, but still had the same issue.
Unless you are worried about name conflicts between existing C++ function names and the C library, how about just using extern "C" (in your C++ code) and call it (from your C or C++ code). For example:
extern "C" void f(int); // apply to a single function
extern "C" { // or apply to a block of functions
int g(double);
double h(void);
};
void code(int i, double d)
{
f(i);
int ii = g(d);
double dd = h();
// ...
}
When code is enclosed within an extern “C” block, the C++ compiler ensures that the function names are un-mangled – that the compiler emits a binary file with their names unchanged, as a C compiler would do.
This approach is commonly used to accommodate inter language linkage between C++ and C.
from this Reference
more from cppprefference.com
You could try this:
// lib.hpp
namespace foo {
constexpr auto bar = foobar;
}
This should create a function pointer, and because it is constexpr, it should get resolved at compile time, so no performance hit. Also, constexpr is implicitly inline, so that (or static) can be omitted from this definition.
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);
}
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.
Consider the following function defined in a C library:
void f(void (*callback)(int)) { callback(0); }
which will be called from a C++11 program defining the callback() as below:
struct S {
static void S::callback(int) noexcept {}
};
f(&S::callback);
Most compiler would probably compiler the above without any warnings, but, my question is, if strictly speaking, I must declare the callback as (a free) extern "C" function to be totally compliant with C++11 standard.
Specifications as extern "C" are for control of the names of functions, variables etc. But in your case S::callback address is passed as the argument in runtime, so the name of the function is not relevant, and no specification is necessary.
This question already has answers here:
C linkage for function pointer passed to C library
(2 answers)
Closed 9 years ago.
Are pointers to (non-member) C++ functions compatible between C++ and C ?
Given e.g. C code that does
void doit(void (*cb)(int i))
{
cb(100);
}
Can the do_it function (which would have C linkage) be called from C++ code
with a C++ function pointer e.g.:
namespace {
void my_function(int i) {
//...
}
void other_function() {
doit(my_function);
}
};
where my_function is a non-member function, or a static member function ?
I suppose this must mean the calling convention is the same for C and C++ code for that to work
- is that guaranteed ?
Or does the C++ code need C linkage to the function passed as a pointer to doit,
e.g.
namespace {
extern "C" {
void my_function(int i) {
//...
}
}
void other_function() {
doit(my_function);
}
};
As far as I'm aware (and for common types of processor architectures), as long as the function is a "free function" or "static member function", it will have the same calling convention in C++ and C. It is only naming convention that changes with that type of function. When you pass a function as a parameter to the another function, it is not using the name of the function (beyond the immediate compilation, that is) to determine which function it is - it's just an address of a function at that point.
So it should be perfectly fine to do your first option.
Technically, the function must have extern "C" linkage in order to be passed as a pointer to a function expecting a C-linkage function pointer. With that said, the compilers I've worked with have no problem accepting global functions and static member functions without explicit C linkage.
Note, however, that extern "C" also disables name mangling. This means that notwithstanding your anonymous namespace, if you do explicitly specify extern "C", a function named my_function in a different translation unit may lead to a multiply defined symbol when linking.
You can if it isn't a class function of course.
Else you need to specifiy the classname in your pointer name.