我试图了解C代码到WebAssembly和JavaScript互操作的转换是如何在后台工作的。我在从函数参数中获取一个简单字符串时遇到了问题。
我的程序是一个简单的Hello World,我正在尝试"模仿"printf
/puts
。
或多或少是我想要构建的C等价物:
int main() {
puts("Hello Worldn");
}
你可以在这里看到一个工作示例。
我目前最好的想法是一次读取16位的内存块(因为wasm似乎以16位的间隔分配它们(,并检查null terminaton。
function get_string(memory, addr) {
var length = 0;
while (true) {
let buffer = new Uint8Array(memory.buffer, addr, 16);
let term = buffer.indexOf(0);
length += term == -1 ? 16 : term;
if (term != -1) break;
}
const strBuf = new Uint8Array(memory.buffer, addr, length);
return new TextDecoder().decode(strBuf);
}
但这似乎真的很笨拙。如果你只知道起始地址,有没有更好的方法从内存中读取字符串?
我一次只读16位的数据块真的有必要吗?如果创建一个类型化的内存数组算作访问整个内存,或者只有当我试图从数组中获取数据时才会发生这种情况,我找不到任何信息。
WebAssembly在64k页中分配内存。也许这就是16位的由来,因为16位可以寻址64千字节。然而,这与手头的任务无关,因为WebAssembly内存只是一个连续的地址空间,所以memory
对象和给定大小的ArrayBuffer
之间没有太大区别(如果有的话(。
一次16字节的窗口也不是必需的(不知何故,16位变成了16字节(。
您可以在没有任何性能损失的情况下简单地执行此操作,并以以下方式创建缓冲区其余部分的视图:
function get_string(memory, addr) {
let buffer = new Uint8Array(memory.buffer, addr, memory.buffer.byteLength - addr);
let term = buffer.indexOf(0);
return new TextDecoder().decode(buffer.subarray(0, term));
}