You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java FFM API传递void**类型的参数?

如何使用Java FFM API传递void**类型参数?

原生C函数定义

void initHandle(void* handle);
void useHandles(void** handles);

你的问题代码

var LINKER = Linker.nativeLinker();
var SYM_LOOKUP = SymbolLookup.loaderLookup().or(LINKER.defaultLookup());
var INIT_HANDLE = LINKER.downcallHandle(SYM_LOOKUP.find("init_handle").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));
var USE_HANDLES = LINKER.downcallHandle(SYM_LOOKUP.find("use_handles").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));

try (var arena = Arena.ofConfined()) {
    List<MemorySegment> handleList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        var handle = arena.allocate(ADDRESS);
        INIT_HANDLE.invokeExact(handle);
        handleList.add(handle);
    }

    // ...

    var handlesHandle = arena.allocate(ADDRESS, handleList.size());
    for (int i = 0; i < handleList.size(); i++) {
        handlesHandle.setAtIndex(ADDRESS, i, handleList.get(i).get(ADDRESS, 0));
    }
    USE_HANDLES.invokeExact(handlesHandle.get(ADDRESS, 0)); // 这里出错
}

问题原因与修正

你调用USE_HANDLES时的参数传递错误:

  • void** handles本质是指向指针数组的指针,对应Java FFM里的MemorySegment(表示数组的首地址)。
  • 你代码里的handlesHandle.get(ADDRESS, 0)是取了指针数组第一个元素的值(也就是第一个句柄的地址),这并不是useHandles需要的数组指针本身。

修正后的完整代码如下:

var LINKER = Linker.nativeLinker();
var SYM_LOOKUP = SymbolLookup.loaderLookup().or(LINKER.defaultLookup());
var INIT_HANDLE = LINKER.downcallHandle(SYM_LOOKUP.find("init_handle").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));
var USE_HANDLES = LINKER.downcallHandle(SYM_LOOKUP.find("use_handles").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));

try (var arena = Arena.ofConfined()) {
    List<MemorySegment> handleList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        var handle = arena.allocate(ADDRESS);
        INIT_HANDLE.invokeExact(handle);
        handleList.add(handle);
    }

    // 分配存储指针数组的内存,大小为handleList.size()个ADDRESS类型
    var handlesArray = arena.allocate(ADDRESS, handleList.size());
    // 将每个初始化后的句柄地址写入数组
    for (int i = 0; i < handleList.size(); i++) {
        // 取出initHandle设置的实际句柄地址
        MemoryAddress handleAddr = handleList.get(i).get(ADDRESS, 0);
        handlesArray.setAtIndex(ADDRESS, i, handleAddr);
    }

    // 直接传递数组的首地址(对应void**)给useHandles
    USE_HANDLES.invokeExact(handlesArray);
}

关键说明

  • arena.allocate(ADDRESS, handleList.size()):分配一块内存,用来存储handleList.size()个指针(每个指针大小是ADDRESS),对应原生的void*[]数组。
  • handlesArray本身就是这个数组的首地址,完全匹配原生的void**类型,直接传给useHandles即可。
  • 你之前填充数组的逻辑是正确的(取出每个handle里存储的实际句柄地址写入数组),问题仅在于最后一步的参数传递。

内容的提问来源于stack exchange,提问作者Eng.Fouad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:03:21