Kotlin/Native与C的互操作性

官方教程 Interoperability with C | Kotlin Documentation

1.类型映射

基本类型

C Kotlin
char kotlin.Byte
unsigned char kotlin.UByte
short kotlin.Short
unsigned short kotlin.UShort
int kotlin.Int
unsigned int kotlin.UInt
long long kotlin.Long
unsigned long long kotlin.ULong
float kotlin.Float
double kotlin.Double

指针类型

C Kotlin
void* COpaquePointer = CPointer<CPointed>
xxx* CPointer<xxx>
const char* kotlin.String

结构体 Struct 联合体 Union

C Kotlin
struct CValue<MyStruct>
union CValue<MyUnion>

2.指针操作

取址/取值

C Kotlin
取址 & ptr
取值 * pointed

指针间强制转换

reinterpret<目标指针类型,不包含最外层CPointer>

例子

val ctx = allocPointerTo<AVFormatContext>() // AVFormatContext * 的kotlin值封装 CPointerVar
ctx.ptr     // 相当于 &ctx ,类型是 AVFormatContext **  指针的指针
ctx.value   // 解kotlin封装,现在是 AVFormatContext *   CPointerVar -> CPointer
ctx.pointed //  相当于 *ctx,类型是 AVFormatContext     结构体

3.内存操作

  • alloc 方法在memScoped环境中,退出Scope会自动free
  • 申请全局内存则使用nativeHeap,需要手动alloc free
  • 动态库中申请的内存不要直接用nativeHeap.free!需要释放内存请调用具体动态库中的free方法。具体原因看这里 C/C++开发常见错误及解决方案
  • kotlin内存(如ByteArray)需要传递给C使用,需要 usePinned { it.addressOf(0) } 获取指针

4.一些kotlin的拓展方法

// Cstr 和 kotlin.String 互转
fun CPointer<ByteVar>.toKString(): String
val String.cstr: CValuesRef<ByteVar>
val cString = kotlinString.cstr.getPointer(nativeHeap)

// 在kotlin中声明一个C的函数回调,不能捕获局部变量
fun <R> staticCFunction(@VolatileLambda function: () -> R): CPointer<CFunction<() -> R>>

// CPointer<CFunction>可以直接执行
fun <R> CPointer<CFunction<() -> R>>.invoke(): R

其他

  • 不想到处都是@ExperimentalForeignApi 则可以在 build.gradle.kts 中添加如下内容
kotlin {
    compilerOptions {
        freeCompilerArgs.add("-opt-in=kotlinx.cinterop.ExperimentalForeignApi")
    }
}
  • 截至 2025/04/05 IntelliJ IDEA 2024.3.5不支持在K2模式下解析cnames.structs.*,疑似是一个遗留很久的bug,暂时只能使用K1