【问题标题】:Passing a JavaScript array of strings to a C function with Emscripten使用 Emscripten 将 JavaScript 字符串数组传递给 C 函数
【发布时间】:2018-03-26 19:42:51
【问题描述】:

我是 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"]

C

char **myCFunc(char **input) {
    // do some processing. Specifically some md5 hashing...
    return output;
}

我的猜测是,我不能自己将多维数组从 JS 传递给 C 函数,而是必须使用 WebAssembly 堆内存。 我知道emscripten JS API 支持这种东西,但我已经很久没有写过C 语言了,这种指针操作的细节目前超出了我的范围。

【问题讨论】:

标签: javascript c emscripten webassembly


【解决方案1】:

这里有两个问题:一个是如何将数据数组传递给 C 函数,另一个是如何从 C 函数中获取数据数组。

对于第一个问题,您需要将每个 JS 字符串转换为 C 字符串,为包含每个此类 C 字符串的数组分配 C 内存,并将值写入数组 - 然后您可以将其传递给您的函数.

例如:

emcc 标志:

-s EXPORTED_FUNCTIONS="['UTF8ToString','stringToUTF8Array','lengthBytesUTF8']"

-s EXTRA_EXPORTED_RUNTIME_METHODS="['_free','_malloc','setValue']"

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 https://stackoverflow.com/a/23917034
  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;
}

对于第二个问题,您的 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);
}

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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 2019-08-22
    • 2015-09-09
    • 2013-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多