![](/img/trans.png)
[英]What do you call a function that takes a value and returns a function that returns that value?
[英]How do you call a C function that takes (or returns) a struct by value from JS via Emscripen/Wasm?
Emscripten docs( https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#通过引用将结构,数组和字符串从Javascript传递给C的情况相当不错。 与代码直接功能调用进行交互 )。
但是按价值传递结构呢? 如果我有这样的C函数:
typedef struct {double a, b, c;} MyStruct;
MyStruct Foo(const MyStruct x, double y);
我怎么称呼Foo并解码结果? (使用Module.cwrap或直接调用Module._Foo)。 我需要访问Emscripten堆栈来做到这一点吗? 记录在哪里?
Module._malloc()
, Module.writeArrayToMemory()
和Module.ccall()
可用,但是非常复杂。
使用C ++进行包装和嵌入更加容易。
// em++ --bind test.cpp -o test.js
#include <emscripten.h>
#include <emscripten/bind.h>
using namespace emscripten;
struct MyStruct {
double a, b, c;
};
MyStruct Foo(const MyStruct x, double y) {
MyStruct r;
r.a = x.a;
r.b = x.b;
r.c = y;
return r;
}
EMSCRIPTEN_BINDINGS(my_struct) {
class_<MyStruct>("MyStruct")
.constructor<>()
.property("a", &MyStruct::a)
.property("b", &MyStruct::b)
.property("c", &MyStruct::c)
;
function("Foo", &Foo);
}
并从JavaScript调用。
var x = new Module.MyStruct();
x.a = 10;
x.b = 20;
x.c = 30;
var y = Module.Foo(x, 21);
console.log(y, y.a, y.b, y.c);
x.delete();
y.delete();
您也可以在堆栈上分配内存 ,并ccall
。
var sp = Module.Runtime.stackSave();
var ret = Module.allocate(24, 'i8', Module.ALLOC_STACK);
var ptr_a = Module.allocate(24, 'i8', Module.ALLOC_STACK);
Module.HEAPF64[(ptr_a >> 3) + 0] = Math.random();
Module.HEAPF64[(ptr_a >> 3) + 1] = Math.random();
Module.HEAPF64[(ptr_a >> 3) + 2] = Math.random();
Module.ccall("Foo",
'number',
['number', 'number', 'number'],
[ret, ptr_a, 21]
);
console.log(
sp,
Module.HEAPF64[(ret >> 3) + 0],
Module.HEAPF64[(ret >> 3) + 1],
Module.HEAPF64[(ret >> 3) + 2]);
Module.Runtime.stackRestore(sp);
这是可能的,以及它是如何工作的:
结构体:
typedef struct {
size_t a;
double b;
} my_struct_t;
按值传递(C):
size_t my_struct_get_a(my_struct_t my) {
return my.a;
}
按值传递(Wasm):
(func $func3 (param $var0 i32) (result i32)
get_local $var0
i32.load
)
通过指针(C)传递:
size_t my_struct_ptr_get_a(const my_struct_t* my) {
return my->a;
}
通过指针传递(Wasm):
(func $func5 (param $var0 i32) (result i32)
get_local $var0
i32.load
)
WebAssembly代码是一样的!
按值返回(C):
my_struct_t my_struct_create(size_t a, double b) {
return (my_struct_t){a, b};
}
按值返回(Wasm):
(func $func1 (param $var0 i32) (param $var1 i32) (param $var2 f64)
get_local $var0
get_local $var2
f64.store offset=8
get_local $var0
get_local $var1
i32.store
)
要注意的是WASM不含result
,有3 param
秒。
为了进行比较,请检查替代功能:
void my_struct_fill(my_struct_t* my, size_t a, double b) {
my->a = a;
my->b = b;
}
Wasm等于先前的功能:
(func $func2 (param $var0 i32) (param $var1 i32) (param $var2 f64)
get_local $var0
get_local $var2
f64.store offset=8
get_local $var0
get_local $var1
i32.store
)
请注意,此方法适用于WebAssembly,未检查asm.js。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.