【问题标题】:Working with memory to fetch string yields incorrect result使用内存来获取字符串会产生不正确的结果
【发布时间】:2019-03-22 07:21:20
【问题描述】:

我正在关注这里的解决方案: How can I return a JavaScript string from a WebAssembly function 和这里: How to return a string (or similar) from Rust in WebAssembly?

但是,当从内存中读取时,我没有得到想要的结果。

AssemblyScript 文件,helloWorldModule.ts:

export function getMessageLocation(): string {
    return "Hello World";
 }

index.html:

 <script>
    fetch("helloWorldModule.wasm").then(response =>
    response.arrayBuffer()
   ).then(bytes =>
      WebAssembly.instantiate(bytes, {imports: {}})
    ).then(results => { 
        var linearMemory = results.instance.exports.memory;
        var offset = results.instance.exports.getMessageLocation();
        var stringBuffer = new Uint8Array(linearMemory.buffer, offset, 11);

        let str = '';
        for (let i=0; i<stringBuffer.length; i++) {
            str += String.fromCharCode(stringBuffer[i]);
        }
    debugger;
    });
  </script>

这会返回 32 的偏移量。最后会产生一个字符串,该字符串开始得太早,并且在“Hello World”的每个字母之间都有空格:

但是,如果我将数组更改为 Int16Array,并在偏移量(即 32)上加 8,则偏移量为 40。像这样:

  <script>
    fetch("helloWorldModule.wasm").then(response =>
      response.arrayBuffer()
    ).then(bytes =>
      WebAssembly.instantiate(bytes, {imports: {}})
    ).then(results => { 
        var linearMemory = results.instance.exports.memory;
        var offset = results.instance.exports.getMessageLocation();
        var stringBuffer = new Int16Array(linearMemory.buffer, offset+8, 11);

        let str = '';
        for (let i=0; i<stringBuffer.length; i++) {
            str += String.fromCharCode(stringBuffer[i]);
        }
        debugger;
    });
  </script>

然后我们得到正确的结果:

为什么第一组代码不像我提供的链接中那样工作?例如,为什么我需要将其更改为与 Int16Array 一起使用以消除“H”和“e”之间的空格?为什么要在偏移量上加 8 个字节?

总之,这里到底发生了什么?

编辑:另一个线索是,如果我在 UInt8 数组上使用 TextDecoder,则解码为 UTF-16 看起来比解码为 UTF-8 更正确:

【问题讨论】:

  • 您似乎找到了问题的答案。您应该考虑将您发现的内容添加为自我回答。
  • 我会在弄清楚为什么使用 16 位数组意味着需要在函数返回的偏移量上加 8 时这样做

标签: javascript webassembly assemblyscript


【解决方案1】:

AssemblyScript 使用 utf-16:https://github.com/AssemblyScript/assemblyscript/issues/43

另外,AssemblyScript 将字符串的长度存储在前 32 位或 64 位中。

这就是我的代码行为不同的原因。本文顶部链接中的示例是针对 C++ 和 Rust,它们以不同的方式进行字符串编码

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 2020-12-14
    • 2015-10-12
    相关资源
    最近更新 更多