将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
额外验证点
- 确认
nelems的准确性:确保Kotlin里的nelems和JNA代码里的len是同一个值,也就是属性实际包含的字符串数量,避免数组长度不匹配导致读取空地址。 - 检查
nc_free_string的绑定:这个C函数的原型是void nc_free_string(char **strs),所以FFM的函数绑定要对应接收MemorySegment类型的参数,确保能正确释放内存。
内容的提问来源于stack exchange,提问作者John Caron
相关产品推荐
相关产品推荐

