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