KMP Native库中KNativePtr转C类型数组(如int*)及IntArray数据读取异常求助
KMP Native库中KNativePtr转C类型数组(如int*)及IntArray数据读取异常求助
问题回顾
你开发了支持JVM和LinuxX86的KMP库,导出C头文件后,C程序能成功调用大部分库函数(比如readArrayInt、get_nelems能拿到正确的72),但通过get_array获取libnetchdf_kref_kotlin_IntArray后,直接将其pinned字段强转为int*读取数据时,得到的是垃圾值而非预期的数组元素。
问题根源
你误解了libnetchdf_kref_kotlin_IntArray中pinned字段的含义:
这个pinned指针指向的是Kotlin托管的IntArray对象本身的内存地址,而不是数组元素的原生内存起始地址。Kotlin的数组是托管对象,内部包含类型元数据、数组大小等额外信息,元素数据存储在对象的内部偏移位置,直接强转pinned为int*会读取到对象的元数据(也就是你看到的垃圾值)。
解决方案:在KMP库中导出辅助函数获取数组元素指针
要正确拿到可直接访问的原生数组指针,你需要在KMP库中主动导出一个辅助函数,用来暴露IntArray的元素内存地址,而不是直接操作pinned字段。
步骤1:在KMP库中添加导出函数
在你的Kotlin代码中(比如ArrayIntSection类或者顶层函数)添加以下代码,导出获取IntArray元素指针的函数:
import kotlinx.cinterop.CPointer import kotlinx.cinterop.IntVar import kotlinx.cinterop.refTo import kotlin.native.ExportForCppRuntime import kotlin.native.CName // 方式1:给ArrayIntSection类添加成员函数 class ArrayIntSection(...) { // 已有代码... @ExportForCppRuntime fun getArrayData(): CPointer<IntVar> { // 返回数组第一个元素的指针,即整个数组的起始地址 return this.array.refTo(0) } } // 方式2:顶层通用函数,可直接处理IntArray @CName("libnetchdf_get_int_array_elements") fun getIntArrayElements(array: IntArray): CPointer<IntVar> { return array.refTo(0) }
步骤2:重新编译KMP库并更新头文件
重新编译后,生成的C头文件会包含新导出的函数声明。比如方式1的函数会被归入ArrayIntSection结构体的函数列表,方式2会作为全局导出函数。
步骤3:修改C程序调用辅助函数
根据你选择的方式,修改C代码来获取正确的数组指针:
方式1(使用ArrayIntSection的成员函数)
libnetchdf_kref_com_sunya_netchdfc_ArrayIntSection arrayIntSection = lib->kotlin.root.com.sunya.netchdfc.readArrayInt(netchdf, variable); int nelems = lib->kotlin.root.com.sunya.netchdfc.ArrayIntSection.get_nelems(arrayIntSection); printf("nelems=%d\n", nelems); // 调用新导出的getArrayData获取数组元素指针 int *data = (int *) lib->kotlin.root.com.sunya.netchdfc.ArrayIntSection.getArrayData(arrayIntSection); for (int idx=0; idx < 5; idx++) { printf(" %d == %d\n", idx, data[idx]); }
方式2(使用顶层通用函数)
libnetchdf_kref_com_sunya_netchdfc_ArrayIntSection arrayIntSection = lib->kotlin.root.com.sunya.netchdfc.readArrayInt(netchdf, variable); int nelems = lib->kotlin.root.com.sunya.netchdfc.ArrayIntSection.get_nelems(arrayIntSection); printf("nelems=%d\n", nelems); libnetchdf_kref_kotlin_IntArray intarray = lib->kotlin.root.com.sunya.netchdfc.ArrayIntSection.get_array(arrayIntSection); // 调用顶层辅助函数获取元素指针 int *data = (int *) libnetchdf_get_int_array_elements(intarray.pinned); for (int idx=0; idx < 5; idx++) { printf(" %d == %d\n", idx, data[idx]); }
额外注意事项
- 内存管理:通过
refTo(0)获取的指针依赖于Kotlin数组对象的生命周期,只要数组对象不被GC回收(你已经通过pinned固定了对象,或者库本身会管理该对象的内存),指针就有效。 - 其他数组类型:对于LongArray等其他数组类型,可参照同样的方式导出对应的辅助函数。
内容来源于stack exchange
相关产品推荐
相关产品推荐

