I'm trying to call a kernel wrapper foo from a C++ class. I've tried to do as suggested here below:
// In CPP.h:
class cls {
extern "C" inline void foo();
}
// In Kernels.cu:
#include "CPP.h"
extern "C" inline void cls::foo() {
// call kernels here
}
but this has not worked - I get a compiler errors:
CPP.h: invalid storage class for a class member
CPP.h: "cls::foo" was referenced but not defined
Kernels.cu: label "cls" was declared but never referenced
What's going wrong?
You shouldn't mark a class method with extern "C".
Make a wrapper non-member function with extern "C" specifier, and let this function call your class's method (you will need to specify an instance also).
Related
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);
}
I tried to create a function which is returning a vector in C++. But when it built to dll, the function name seems to be mangled.
I tried to use the extern C but the problem is return type vector cannot support if I use extern C
Error : C Linkage function cannot return C++ class std:: Vector
Below is the code I am using
class __declspec(dllexport) TestClass
{
public:
string sClassName;
string sName;
string sDescription;
};
extern "C"
{
vector<TestClass> __declspec(dllexport) GetInfoList();
}
We see it is not problem with easy solution. Here's an involved solution. Use a non-mangled name (extern "C") with GetProcAddress to access a special function in the higher level DLL. . Define all the functions you want to call, as virtuals, in an abstract base class. Call that function above to retrieve the pointer P to a lazily instantiated concrete class with virtuals overriden. Invoke desired method through the pointer P.
vector is C++ type and so cannot be directly given under extern "C". Give the function inside a class and export the class as C Type.
extern "C"
{
class __declspec(dllexport) ClassToExport
{
vector<TestClass> GetInfoList();
};
}
Now use this class object to axcess the function.
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.
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 will happen if I "shorten" this call:
GetInstanceOfClass1()->GetInstanceOfClass2();
(where the instance of Class2 is a member of Class1) with a extern function declared in Class1.cpp:
extern void GetInstanceOfClass2()
{
GetInstanceOfClass1()->GetInstanceOfClass2();
}
Will the compiler (clang) produce inefficient code? Is that an ugly, bad idea actually?