在C++杂志上,我有
class MyClass {
public:
MyClass() {}
std::shared_ptr<std::vector<uint8_t>> buffer;
int getPtr() {
return (int)(buffer->data());
}
int getLength() {
return buffer->size();
}
};
EMSCRIPTEN_BINDINGS() {
class_<MyClass>("MyClass").constructor()
.function("getLength",&MyClass::getLength)
.function("getPtr",&MyClass::getPtr,
allow_raw_pointers());
}
我可以从JS中调用getLength()和getPtr(),但是我不知道如何让JS把它当作下载的ArrayBuffer。
如何将缓冲区数据以类似于https://github.com/kennethjiang/js-file-download/blob/master/file-download.js的代码下载到JS中。
发布于 2018-12-03 20:48:53
目前,WebAssembly只定义用于JS和WASM之间通信的基本数字类型。没有对象类型,也没有数组类型。这是WebAssembly的设计目标。 Emscripten做了一些C++类<=> JS绑定的黑客操作,但它们不是WASM标准。
WebAssembly.Memory()
但是有一种方法可以得到数组。即使没有API,JS也可以直接访问WASM模块的内部内存。WASM具有线性存储模型,线性存储器通过WebAssembly.Memory()
接口。WebAssembly.Memory()
是一个ArrayBuffer WebAssembly.Memory.buffer
,您的WASM模块使用它作为堆内存区域,并在其中进行内存分配(例如malloc()
)。
1.以UInt8Array的形式访问它
什么意思?这意味着从getPtr()
WebAssembly.Memory.buffer
**.**获得的指针( JS端的整数)实际上是对WebAssembly.Memory.buffer
**.**的偏移量。
Emscripten自动生成JS (这是由一个名为preamble.js的模板生成的)代码,该代码创建了WebAssembly.Memory()
。您可以自己搜索Emscripten生成的代码,并且应该能够找到类似的到这条线行。
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });
这样,您就可以通过ArrayBuffer访问WASM模块使用的Module['wasmMemory'].buffer
。
let instance = new Module.MyClass();
// ... Do something
let ptr = instance.getPtr();
let size = instance.getLength();
// You can use Module['env']['memory'].buffer instead. They are the same.
let my_uint8_buffer = new Uint8Array(Module['wasmMemory'].buffer, ptr, size);
2. Emscripten HEAPU8
或者,Emscripten提供作为类型化数组访问堆内存区域的正式方法:HEAPU8
、HEAPU16
、HEAPU32
等定义的这里。所以你可以这样做:
let instance = new Module.MyClass();
// ... Do something
let ptr = instance.getPtr();
let size = instance.getLength();
let my_uint8_buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, size);
使用HEAPU8
会更安全,因为HEAPU8
是文档化的,而Module['wasmMemory']
的属性名称则有点无文档化,并且可能会被更改;但是它们也会做同样的事情。
3.使用emscripten::val
(仅限C++)
Emscripten还为emscripten::val
开发人员提供了一个名为C++的类,用于JS和C++之间的交互。为了方便起见,本文对任何JS/C++类型进行了抽象。您可以使用此方法获取数组。
以下是文献资料和Glenn的评论中的例子:
#include <emscripten/bind.h>
#include <emscripten/val.h>
emscripten::val getInt8Array() {
return emscripten::val(
emscripten::typed_memory_view(buffer->size(),
buffer->data()));
}
EMSCRIPTEN_BINDINGS() {
function("getInt8Array", &getInt8Array);
}
然后,您可以在JS端调用getInt8Array()
来获取类型化数组。
结论
这里有3个选项建议从WASM获取数组。无论如何,我认为您应该理解WebAssembly.Memory
的概念和选项1后面的内容,因为这是从WASM获取数组的最低级别,最重要的是,WASM是非托管和不安全的内存访问,这样在C/C++方面释放或修改对象时,很容易破坏数据。对于这一具体情况,需要了解低层次的含义。
发布于 2022-03-11 00:13:23
我刚刚解决了这件事。定义一个自定义Module.print
,通过printf
语句捕获数据。我的例子:
C++
bool first = true;
for (auto i : settings)
{
if (!first)
{
printf(",");
}
first = false;
printf("%u", i);
}
printf("\n");
(这将打印一些看起来像1,255,76,31
的东西)
JS:(需要在包含<script>
输出.js
的.js
标记之前定义以下内容)
let arrayFromC;
var Module = {
preRun: [],
postRun: [],
print: function (printOutput) {
arrayFromC = printOutput.split(",");
},
};
https://stackoverflow.com/questions/53602955
复制