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