最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Emscripten: Calling a C function that modifies array elements - Stack Overflow

programmeradmin1浏览0评论

I have a simple C function that modifies elements of an integer array. I can convert it to JavaScript using Emscripten (emcc) without problems. But when I call the function on a JS array, the values in it do not seem to change. Please help.

This is the C function definition:

/* modify_array.c */
void modify_array(int X[8]) {
  int i;
  for (i = 0; i < 8; ++i) {
    X[i] += 1;
  }
}

This is the mand I used to transpile the C code to JS:

emcc modify_array.c -o modify_array.js -s EXPORTED_FUNCTIONS="['_modify_array']"

And this is the JavaScript (Node.js) code for invoking the transpiled JS code:

var mod = require("./modify_array.js");
var f = mod.cwrap("modify_array", "undefined", ["array"]);

var X = [0, 1, 2, 3, 4, 5, 6, 7];
var bytesX = new Uint8Array(new Int32Array(X).buffer);

/* Invoke the emscripten-transpiled function */
f(bytesX);


console.log(new Int32Array(bytesX.buffer));

After running the JS code, the buffer contains values that are identical to the original values, not the incremented values. Why? How can I get the updated values?

I have a simple C function that modifies elements of an integer array. I can convert it to JavaScript using Emscripten (emcc) without problems. But when I call the function on a JS array, the values in it do not seem to change. Please help.

This is the C function definition:

/* modify_array.c */
void modify_array(int X[8]) {
  int i;
  for (i = 0; i < 8; ++i) {
    X[i] += 1;
  }
}

This is the mand I used to transpile the C code to JS:

emcc modify_array.c -o modify_array.js -s EXPORTED_FUNCTIONS="['_modify_array']"

And this is the JavaScript (Node.js) code for invoking the transpiled JS code:

var mod = require("./modify_array.js");
var f = mod.cwrap("modify_array", "undefined", ["array"]);

var X = [0, 1, 2, 3, 4, 5, 6, 7];
var bytesX = new Uint8Array(new Int32Array(X).buffer);

/* Invoke the emscripten-transpiled function */
f(bytesX);


console.log(new Int32Array(bytesX.buffer));

After running the JS code, the buffer contains values that are identical to the original values, not the incremented values. Why? How can I get the updated values?

Share Improve this question edited Jan 28, 2015 at 21:48 Shanqing Cai asked Jan 28, 2015 at 21:28 Shanqing CaiShanqing Cai 3,8863 gold badges26 silver badges37 bronze badges 7
  • Shouldn't you pass a pointer and an array size in C instead? – zerkms Commented Jan 28, 2015 at 21:35
  • @zerkms: I tried the C function signature modify_array(int *X, int size), then did the emscripten workflow again, with modifications to the JavaScript syntax of course. The behavior appears to be exactly the same as the original array-based C function signature. – Shanqing Cai Commented Jan 28, 2015 at 21:43
  • Could you show modify_array.js contents? – zerkms Commented Jan 28, 2015 at 21:44
  • @zerkms, Thanks for the suggestion. But I don't see how that might be helpful. The size of the generated file is pretty large (9.8k lines) and the code is not very human-readable. If you want, I can PM it to you (if there is such a thing on StackOverflow). – Shanqing Cai Commented Jan 28, 2015 at 21:46
  • 1 That is correct, @zerkms. This is apparently how Emscripten works... After a little more searching on StackOverflow (which I probably should have done beforehand), I found this Q+A: stackoverflow./questions/17883799/…. This solves my problem. Using Module._malloc to create a chunk of heap memory, specifying the JS argument as "number" and passing it to the JS function does the trick. Later you can use "getValue" or "subArray" to retrieve the new values in the same heap memory location. – Shanqing Cai Commented Jan 28, 2015 at 22:21
 |  Show 2 more ments

1 Answer 1

Reset to default 9

Emscripten's memory model is a single flat array. That means that when you provide an array of data to a piled C method, it is copied into the single array, which is the only place it can be accessed (the ccall/cwrap methods do this for you). In other words, all arguments you pass are by value, not by reference, even if they are arrays (which in JS normally are passed by reference).

To work within the emscripten memory model, you can use memory in the single flat array,

var ptr = Module._malloc(8);
var view = Module.HEAPU8.subarray(ptr, ptr+8);
var f = Module.cwrap("modify_array", "undefined", ["number"]);
f(ptr);

That reserves a space in the single array, and using a subarray on the single array, we can access its values. Note the use of number as the type. We are passing ptr, which is a pointer to the buffer. As a pointer, it is just a number referring to a location in the single array.

(Note that you should call free to release the memory at the right time.)

发布评论

评论列表(0)

  1. 暂无评论