Javascript 如何处理向emscripten编译代码传递/返回数组指针?

Javascript 如何处理向emscripten编译代码传递/返回数组指针?,javascript,emscripten,Javascript,Emscripten,我不熟悉Emscripten/javascript以及这个超负荷社区。如果我的情况已经得到解决,我提前道歉 在Windows7环境中,我使用emcc编译了一个简单的c程序,该程序接受数组并对其进行修改(见下文) 加载后,我看到在浏览器窗口中生成的输出与预期一致(见下文) 但是,当通过javascript控制台使用module.cwrap()命令并尝试直接调用函数(在main()之外)时 我看到浏览器中生成/显示了以下内容,这不是我期望看到的 doubleVector[0] = 0.000000

我不熟悉Emscripten/javascript以及这个超负荷社区。如果我的情况已经得到解决,我提前道歉

在Windows7环境中,我使用emcc编译了一个简单的c程序,该程序接受数组并对其进行修改(见下文)

加载后,我看到在浏览器窗口中生成的输出与预期一致(见下文)

但是,当通过javascript控制台使用module.cwrap()命令并尝试直接调用函数(在main()之外)时

我看到浏览器中生成/显示了以下内容,这不是我期望看到的

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   
我有以下问题:

  • 调用Module.cwrap()时,返回类型和参数列表的语法是否正确?我在教程的“与代码交互”部分成功地运行了简单、直接的int_sqrt()示例,该部分涉及将非指针变量传递给int_sqrt()例程

  • 当数组和/或指针传递给(或从)emscripten生成的javascript代码时,是否会发生一些不同的情况

  • 当从main()调用函数displayArray()时,在浏览器中生成的输出如何工作(如预期);但不是通过javascript控制台

  • 我是Emscripten/javascript新手,因此非常感谢您提供的任何信息/帮助

    谢谢,


    FC

    Module.cwrap的预期格式允许将“array”传递到函数中,但会在结果时断言,如果尝试返回数组,则会失败

    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代码所针对的堆之外,并且与传入参数中预期的原始指针类型不匹配

    有几种方法可以访问数组以将数据传递给函数。所有这些都要求EmScrippen知道您的内存在emscripten Module.HEAP*中的位置,因此最初的步骤是在某个时候调用emscripten“_malloc”函数

    var offset = Module._malloc(24)
    
    这将允许您在Emscripten堆中分配3x 8字节双数组所需的24字节,并返回Emscripten堆中的数字偏移量,表示为数组保留的U8 TypedArray偏移量。此偏移量是指针,当配置为使用原始指针偏移量时,它将自动传递到cwrap displayArray函数中

    displayArray=Module.cwrap('displayArray','number',['number'])
    
    此时,如果希望访问或修改数组的内容,只要malloc有效,您至少有以下选项:

  • 使用临时包装的Float64数组设置内存,除了以下两种访问方法外,没有简单的方法恢复该值

    Module.HEAPF64.set(new Float64Array([1,2,3]), offset/8);
    displayArray(offset);
    
  • Module.setValue将使用“double”提示自动修改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
    
  • 如果希望在Javascript端更广泛地使用指针,可以手动从HEAPF64项中提取子数组类型Darray。这允许您在完成函数执行后轻松读取值。此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
    

  • 作为对另一个答案的补充,这里有一个方便的函数,用于分配
    float64
    数组

    function cArray(size) {
        var offset = Module._malloc(size * 8);
        Module.HEAPF64.set(new Float64Array(size), offset / 8);
        return {
            "data": Module.HEAPF64.subarray(offset / 8, offset / 8 + size),
            "offset": offset
        }
    }
    var myArray = cArray(3) // {data: Float64Array(3), offset: 5247688}
    
    
    var displayArray = Module.cwrap('displayArray','number',['number'])
    displayArray(myArray.offset)
    
    给出原始函数的输出:

    doubleVector[0] = 98.000000
    doubleVector[1] = 99.000000
    doubleVector[2] = 100.000000
    modified doubleVector[0] = 98.000000
    doubleVector[1] = 99.000000
    modified doubleVector[2] = 100.000000
    

    非常有用的回答。省去了我几个小时的头发拉扯。谢谢。确实很有帮助,但是“另一条路”呢?如何从C代码修改数组并在Javascript中使用它?我看到了
    Module.malloc()
    ,但没有
    Module.free()
    ?它是由JS的GC处理的吗?@Nikkolasg否,您必须调用
    模块。_free(…)
    。为什么要将偏移量除以8?偏移量不是已经指向正确的位置了吗?我在angular 8中遇到了同样的问题。我尝试使用WebAssembly模块导入WASM文件。但我不确定如何得到“模块”对象。对我来说,它说的是未定义的。
    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
    
    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
    
    function cArray(size) {
        var offset = Module._malloc(size * 8);
        Module.HEAPF64.set(new Float64Array(size), offset / 8);
        return {
            "data": Module.HEAPF64.subarray(offset / 8, offset / 8 + size),
            "offset": offset
        }
    }
    var myArray = cArray(3) // {data: Float64Array(3), offset: 5247688}
    
    
    var displayArray = Module.cwrap('displayArray','number',['number'])
    displayArray(myArray.offset)
    
    doubleVector[0] = 98.000000
    doubleVector[1] = 99.000000
    doubleVector[2] = 100.000000
    modified doubleVector[0] = 98.000000
    doubleVector[1] = 99.000000
    modified doubleVector[2] = 100.000000