我有如下C代码:
int stringlen(char* p){
return strlen(p);
}
我使用Emscripten编译器进行编译:emcc -s EXPORTED_FUNCTIONS="['_stringlen']" example.c -o example.js
然后,在Node.js中,我调用编译后的函数em_module1._stringlen('sadfsa')
。不幸的是,该函数返回4
而不是6
(字符串'sadfsa'
的正确长度)。
如何正确地将char*
从Node.js传递到此编译函数?
带有Web内部功能_stringlen()
的已编译WebAssembly模块使用其内存表示为linear memory。编译后的函数仅知道其模块的内存。因此,指针char*
必须指向模块的内存块。
我们将保留完整的C代码,但添加缺少的内容包括:
#include <string.h>
int stringlen(char *p)
{
return strlen(p);
};
输出的JavaScript代码example.js
包含内存管理等功能。接下来,在test.js
脚本中,我们:
UInt8Array
)\0
字符]HEAPU8
)const Module = require('./example.js');
const str_raw = new TextEncoder().encode('Lorem ipsum'); // 1)
let ptr = Module._malloc(str_raw.length); // 2)
let chunk = Module.HEAPU8.subarray(ptr, ptr + str_raw.length); // 3A)
chunk.set(str_raw); // 3B)
console.log(Module._stringlen(chunk.byteOffset));
Module._free(ptr); // 4)
对于编译,我已强制对WebAssembly模块(-s WASM_ASYNC_COMPILATION=0
)进行同步编译,以确保在require()
之后该模块将准备就绪。
emcc -s EXPORTED_FUNCTIONS="['_stringlen']" example.c -o example.js -s WASM_ASYNC_COMPILATION=0
我们按照node test.js
执行脚本。
我最喜欢的解决方案是已经提到的embind。它要求您使用C ++:
#include <string>
#include <emscripten.h>
#include <emscripten/bind.h>
size_t stringlen(std::string p)
{
return p.size();
};
EMSCRIPTEN_BINDINGS(Module)
{
emscripten::function("stringlen", &stringlen);
}
我们通过使用带有--bind
标志的embind来编译代码:
emcc example.cpp -o example.js -s WASM_ASYNC_COMPILATION=0 -std=c++11 --bind
现在函数调用更加简单:
const Module = require('./example.js');
console.log(Module.stringlen('Lorem ipsum'))