使用内存获取字符串会产生不正确的结果
Working with memory to fetch string yields incorrect result
我正在关注这里的解决方案:
和这里:
但是,当从内存中读取时,我没有得到想要的结果。
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>
这个 returns 偏移量为 32。最后生成一个字符串,它开始得太早并且在 "Hello World" 的每个字母之间有 spaces:
但是,如果我将数组更改为 Int16Array,并将 8 添加到偏移量(原来是 32),则偏移量为 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" 之间的 space?为什么我需要在偏移量上增加 8 个字节?
综上所述,这到底是怎么回事?
编辑:另一个线索是,如果我在 UInt8 数组上使用 TextDecoder,解码为 UTF-16 看起来比解码为 UTF-8 更正确:
AssemblyScript 使用 utf-16:https://github.com/AssemblyScript/assemblyscript/issues/43
此外,AssemblyScript 将字符串的长度存储在前 32 位或 64 位中。
这就是我的代码行为不同的原因。 post 顶部链接中的示例适用于 C++ 和 Rust,它们以不同的方式进行字符串编码
我正在关注这里的解决方案:
但是,当从内存中读取时,我没有得到想要的结果。
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>
这个 returns 偏移量为 32。最后生成一个字符串,它开始得太早并且在 "Hello World" 的每个字母之间有 spaces:
但是,如果我将数组更改为 Int16Array,并将 8 添加到偏移量(原来是 32),则偏移量为 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" 之间的 space?为什么我需要在偏移量上增加 8 个字节?
综上所述,这到底是怎么回事?
编辑:另一个线索是,如果我在 UInt8 数组上使用 TextDecoder,解码为 UTF-16 看起来比解码为 UTF-8 更正确:
AssemblyScript 使用 utf-16:https://github.com/AssemblyScript/assemblyscript/issues/43
此外,AssemblyScript 将字符串的长度存储在前 32 位或 64 位中。
这就是我的代码行为不同的原因。 post 顶部链接中的示例适用于 C++ 和 Rust,它们以不同的方式进行字符串编码