2013-07-26 149 views
26

我是Emscripten/javascript以及此Overstack社区的新手。如果我的情况已经得到解决,我很抱歉。如何处理传递/返回数组指针到emscripten编译的代码?

从Windows 7的环境中,我使用EMCC编译它接受一个数组并修改它(见下文)一个简单的C程序。

double* displayArray(double *doubleVector) { 

    for (int cnt = 0; cnt < 3; cnt++) 
     printf("doubleVector[%d] = %f\n", cnt, doubleVector[cnt]); 

    doubleVector[0] = 98; 
    doubleVector[1] = 99; 
    doubleVector[2] = 100; 

    for (int cnt1 = 0; cnt1 < 3; cnt1++) 
     printf("modified doubleVector[%d] = %f\n", cnt1, doubleVector[cnt1]); 

    return doubleVector; 
} 

int main() { 

    double d1, d2, d3; 
    double array1[3]; 
    double *array2; 

    array1[0] = 1.00000; 
    array1[1] = 2.000000; 
    array1[2] = 3.000000; 

    array2 = displayArray(array1); 

    for (int cntr =0; cntr < 3; cntr++) 
     printf("array1[%d] = %f\n", cntr, array1[cntr]); 

    for (int cnt = 0; cnt < 3; cnt++) 
     printf("array2[%d] = %f\n", cnt, array2[cnt]); 

    return 1; 
} 

使用em选项的-o选项,我生成了一个加载到浏览器(Chrome)的.html文件。

python emcc displayArray7.c -o displayArray7.html -s EXPORTED_FUNCTIONS="['_main', '_displayArray' 

加载后,我看到在浏览器窗口中生成的输出如预期的那样(见下文)。

doubleVector[0] = 1.000000 
doubleVector[1] = 2.000000 
doubleVector[2] = 3.000000 
modified doubleVector[0] = 98.000000 
modified doubleVector[1] = 99.000000 
modified doubleVector[2] = 100.000000 
array1[0] = 98.000000 
array1[1] = 99.000000 
array1[2] = 100.000000 
array2[0] = 98.000000 
array2[1] = 99.000000 
array2[2] = 100.000000 

但是,在使用时module.cwrap()经由命令JavaScript控制台并试图直接调用函数(外的主()),

> displayArray=Module.cwrap('displayArray', '[number]', ['[number]']) 

> result = displayArray([1.0,2.0,3.0]) 
[1, 2, 3] 
> result 
[1, 2, 3] 

我看到正在生成以下/显示在浏览器中,这不是我期望看到的。

doubleVector[0] = 0.000000 
doubleVector[1] = 0.000000 
doubleVector[2] = 0.000000 
modified doubleVector[0] = 100.000000 
modified doubleVector[1] = 100.000000 
modified doubleVector[2] = 100.000000 

我有以下问题:

  1. 我是否有语法正确的返回类型和参数列表正确,我呼吁Module.cwrap()?我已经成功地运行与传递非指针变量的int_sqrt()常规交易的教程“与代码交互”一节中int_sqrt()的简单,直接的例子。

  2. 有什么不同的,当数组和/或指针传递给(或返回)emscripten生成的JavaScript代码,是怎么回事?

  3. 如何的是,在该函数的浏览器所生成的输出,displayArray(),工程(如预期)从主调用时();但不是通过JavaScript控制台?

我是新来的Emscripten/JavaScript所以任何信息/援助将不胜感激。

谢谢

FC

回答

32

Module.cwrap的预期格式并允许“数组被传递到函数,但断言对结果和失败,如果你试图返回数组

displayArrayA=Module.cwrap('displayArray','array',['array']) 
displayArrayA([1,2,3]) 
// Assertion failed: ccallFunc, fromC assert(type != 'array') 

的这第二个限制是,进入阵列预计将字节数组,这意味着你需要任何进入双阵列转换成8位无符号数

displayArrayA=Module.cwrap('displayArray','number',['array']) 
displayArrayA(new Uint8Array(new Float64Array([1,2,3]).buffer)) 

以这种方式调用该方法将调用您的函数,将您的数组临时复制到Emscripten堆栈,该堆栈将在调用函数执行后重置,使得返回的数组偏移在释放堆栈空间时可能不可用。

如果你想得到你的函数的结果,在Emscriptens堆系统中分配和保存一个数组更好。

Emscripten代码只能访问已在Emscripten堆空间内分配的内存。您尝试传入该函数的数组将被分配到Emscripten代码所运行的堆的外部,并且与传入参数中预期的原始指针类型不匹配。

有几种方法可以访问数组以将数据传递到函数。所有这些都需要Emscripen掌握emscripten Module.HEAP *内存位置的知识,因此最初的步骤是在某个时刻调用Emscripten“_malloc”函数。

var offset = Module._malloc(24) 

这将允许你在需要为您3倍8字节双阵列Emscripten堆分配所需的24个字节,并返回一个数字在Emscripten堆表示的U8 TypedArray偏移保留您的阵列偏移。这个偏移量是你的指针,当它被配置为使用原始指针偏移量时,它会自动传递到你的cwrap displayArray函数中。

displayArray=Module.cwrap('displayArray','number',['number']) 

在这一点上,如果你想访问或修改数组的内容,只要malloc的是有效的,至少有以下选项:

  1. 设置内存使用暂时缠绕Float64阵列,没有简单的方法来恢复的值除访问的以下2种方法

    Module.HEAPF64.set(new Float64Array([1,2,3]), offset/8); 
    displayArray(offset); 
    
  2. Module.setValue将使用“双”提示自然而然LY修改HEAPF64偏移,除以8

    Module.setValue(offset, 1, 'double') 
    Module.setValue(offset+8, 2, 'double') 
    Module.setValue(offset+16, 3, 'double') 
    displayArray(offset) 
    var result = []; 
    result[0] = Module.getValue(offset,'double'); //98 
    result[1] = Module.getValue(offset+8,'double') //99 
    result[2] = Module.getValue(offset+16,'double') //100 
    
  3. 如果你想在JavaScript端更广泛地利用你的指针,你可以拉一个子数组TypedArray手动开关本HEAPF64条目。这使您可以在完成执行功能后轻松读取值。这TypedArray是由同一个堆作为Emscripten的休息,所以在JavaScript端执行的所有更改将在Emscripten侧,反之亦然反映支持:

    var doublePtr = Module.HEAPF64.subarray(offset/8, offset/8 + 3); 
    doublePtr[0] = 1; 
    doublePtr[1] = 2; 
    doublePtr[2] = 3; 
    // Although we have access directly to the HEAPF64 of the pointer, 
    // we still refer to it by the pointer's byte offset when calling the function 
    displayArray(offset); 
    //doublePtr[] now contains the 98,99,100 values 
    
+2

非常有用的答案。节省我几小时的拉毛。谢谢。 – scai

+0

确实非常有帮助,但是“相反”呢?如何从C代码修改数组并在Javascript中使用它? – gromit190

+0

我看到一个'Module.malloc()'但没有'Module.free()'?它是由JS的GC处理的吗? – Nikkolasg