首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何将C++ uint8_t数组获取到JS Blob或UInt8Array

如何将C++ uint8_t数组获取到JS Blob或UInt8Array
EN

Stack Overflow用户
提问于 2018-12-03 22:31:14
回答 2查看 7K关注 0票数 9

在C++杂志上,我有

代码语言:javascript
代码运行次数:0
运行
复制
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中。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-04 04: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生成的代码,并且应该能够找到类似的到这条线行。

代码语言:javascript
代码运行次数:0
运行
复制
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });

这样,您就可以通过ArrayBuffer访问WASM模块使用的Module['wasmMemory'].buffer

代码语言:javascript
代码运行次数:0
运行
复制
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提供作为类型化数组访问堆内存区域的正式方法HEAPU8HEAPU16HEAPU32等定义的这里。所以你可以这样做:

代码语言:javascript
代码运行次数:0
运行
复制
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的评论中的例子:

代码语言:javascript
代码运行次数:0
运行
复制
#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++方面释放或修改对象时,很容易破坏数据。对于这一具体情况,需要了解低层次的含义。

票数 15
EN

Stack Overflow用户

发布于 2022-03-11 08:13:23

我刚刚解决了这件事。定义一个自定义Module.print,通过printf语句捕获数据。我的例子:

C++

代码语言:javascript
代码运行次数:0
运行
复制
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标记之前定义以下内容)

代码语言:javascript
代码运行次数:0
运行
复制
let arrayFromC;
var Module = {
  preRun: [],
  postRun: [],
  print: function (printOutput) {
    arrayFromC = printOutput.split(",");
  },
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53602955

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档