Bra*_*non 6 javascript c emscripten webassembly
我是WebAssembly和Emscripten的新手,我正在尝试将JavaScript中的字符串数组传递给C函数,以便进一步处理Module.cwrap(...).理想情况下,我还想从C返回一个字符串数组回JavaScript.
下面是我正在寻找的一些伪代码:
JS
const strings = ["foo", "bar", "fool", "gnar"]
const result = Module.cwrap("myCFunc", "array", ["array"])
console.log(result) // ["my", "transformed", "array"]
Run Code Online (Sandbox Code Playgroud)
C
char **myCFunc(char **input) {
// do some processing. Specifically some md5 hashing...
return output;
}
Run Code Online (Sandbox Code Playgroud)
我的猜测是我无法从JS到C函数自己传递多维数组,但是必须使用WebAssembly堆内存.我知道emscripten JS API支持这种类型的东西,但我还没有编写C语言,这种类型的指针操作的细节目前还超出了我的范围.
这里有两个问题:一个是如何将数据数组传递给 C 函数,另一个是如何从 C 函数取回数据数组。
对于第一个问题,您需要将每个 JS 字符串转换为 C 字符串,为保存每个此类 C 字符串的数组分配 C 内存,并将值写入数组 - 然后您可以将其传递给您的函数。
例如:
emcc 标志:
-s EXPORTED_FUNCTIONS="['UTF8ToString','stringToUTF8Array','lengthBytesUTF8']"
-s EXTRA_EXPORTED_RUNTIME_METHODS="['_free','_malloc','setValue']"
Run Code Online (Sandbox Code Playgroud)
JavaScript:
// convert a Javascript string to a C string
function str2C(s) {
var size = lengthBytesUTF8(s) + 1;
var ret = _malloc(size);
stringToUTF8Array(s, HEAP8, ret, size);
return ret;
}
function run_with_strings(strings) {
let c_strings = strings.map(x => str2C(x));
// allocate and populate the array. adapted from /sf/answers/1674192411/
let c_arr = _malloc(c_strings.length*4); // 4-bytes per pointer
c_strings.forEach(function(x, i) {
Module.setValue(argsC + i * 4, x, "i32");
});
// invoke our C function
let rc = myCFunc(c_strings.length, c_arr);
// free c_strings
for(let i = 0; i < c_strings.length; i++)
_free(c_strings[i]);
// free c_arr
_free(c_arr);
// return
return rc;
}
Run Code Online (Sandbox Code Playgroud)
对于第二个问题,您的 C 函数可能很难使用,因为它不返回项目数(尽管我认为您可以推断如果最后一个项目为 NULL 并且没有其他项目为 NULL)。一种解决方案是让您的函数返回一个不透明的指针,然后可以将其反馈到一些辅助函数中,例如:
在C中:
struct myCFuncReturnValue {
char **values;
unsigned int count;
};
struct myCFuncReturnValue *myCFunc(char **input) {
struct myCFuncReturnValue *p = calloc(1, sizeof(*p));
...
p->count = ...;
p->values = ...;
return p;
}
char *myCFunc_value(struct myCFuncReturnValue *p, unsigned int i) {
return i < p->count ? p->values[i] : NULL;
}
unsigned int myCFunc_count(struct myCFuncReturnValue *p) {
return p->count;
}
void myCFunc_destroy(struct myCFuncReturnValue *p) {
// maybe here you need to free each p->values[i];
free(p->values);
free(p);
}
Run Code Online (Sandbox Code Playgroud)
JavaScript:
// continuing with the rc value from run_with_strings():
for(let i = 0, j = myCFunc_count(rc); i < j; i++) {
let c_string = myCFunc_value(rc, i);
console.log(UTF8ToString(c_string));
}
myCFunc_destroy(rc);
Run Code Online (Sandbox Code Playgroud)