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

将JNA代码移植至FFM API时,C库返回String[]出错求助

问题:JNA移植到Java 19 FFM API处理C返回String[]失败

C API定义

int nc_get_att_string(  
    int          ncid,
    int          varid,
    const char * name,
    char **      value) 

注意:与多数nc_get_att函数不同,nc_get_att_string()会分配内存返回给调用方,需用nc_free_string()释放以避免泄漏;同时需预先分配传入的指针数组内存。

可正常运行的JNA实现(Java)

String[] valss = new String[len];
ret = nc4.nc_get_att_string(grpid, varid, attname, valss);
if (ret != 0)
  throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return valss;

失败的FFM API实现(Kotlin)

val strings_p : MemorySegment = session.allocateArray(ValueLayout.ADDRESS, nelems)
checkErr("nc_get_att_string", nc_get_att_string(grpid, varid, attname, strings_p))
val result = mutableListOf<String>()
for (i in 0 until nelems) {
    val s2 : MemoryAddress = strings_p.getAtIndex(ValueLayout.ADDRESS, i) 
    val s = s2.getUtf8String(0)  // 此处出错
    result.add(s)
}
return result

报错信息

Symbol is NULL: MemoryAddress{ offset=0x0 }
java.lang.IllegalArgumentException: Symbol is NULL: MemoryAddress{ offset=0x0 }
    at java.base/jdk.internal.foreign.abi.SharedUtils.checkAddressable(SharedUtils.java:344)
    at java.base/jdk.internal.foreign.abi.SharedUtils.checkAddress(SharedUtils.java:338)
    at java.base/jdk.internal.foreign.MemoryAddressImpl.getUtf8String(MemoryAddressImpl.java:107)
    at sunya.cdm.netcdfClib.NCheader.readAttributeValues(NCheader.kt:365)

问题分析与解决办法

核心错误原因

报错里的NULL地址问题有两个来源:

  • FFM API的getUtf8String方法不允许传入空地址(JNA会自动将NULL转为Java的null字符串,但FFM的校验更严格);
  • 要么你传入的数组长度nelems不正确,导致读到了未初始化的空地址;要么C函数返回的指针数组本身就包含NULL元素。

修正后的代码

先处理空地址判断,同时加上必要的内存释放逻辑:

val strings_p: MemorySegment = session.allocateArray(ValueLayout.ADDRESS, nelems)
checkErr("nc_get_att_string", nc_get_att_string(grpid, varid, attname, strings_p))
val result = mutableListOf<String?>()
try {
    for (i in 0 until nelems) {
        val s2: MemoryAddress = strings_p.getAtIndex(ValueLayout.ADDRESS, i)
        // 先检查是否为空地址,避免触发异常
        val str = if (s2 == MemoryAddress.NULL) {
            null
        } else {
            s2.getUtf8String(0)
        }
        result.add(str)
    }
} finally {
    // 必须调用nc_free_string释放C分配的内存,防止内存泄漏
    nc_free_string(strings_p)
}
return result

额外验证点

  1. 确认nelems的准确性:确保Kotlin里的nelems和JNA代码里的len是同一个值,也就是属性实际包含的字符串数量,避免数组长度不匹配导致读取空地址。
  2. 检查nc_free_string的绑定:这个C函数的原型是void nc_free_string(char **strs),所以FFM的函数绑定要对应接收MemorySegment类型的参数,确保能正确释放内存。

内容的提问来源于stack exchange,提问作者John Caron

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:25:24