【问题标题】:How to avoid the error "staticCFunction must take an unbound..." in Kotlin Native when a Kotlin callback function is called from C?当从 C 调用 Kotlin 回调函数时,如何避免 Kotlin Native 中的错误“staticCFunction must take an unbound ...”?
【发布时间】:2025-12-03 08:35:01
【问题描述】:

这是一个关于回调函数的一般性问题,在 Kotlin Native 中定义,由 C 函数调用。

为了论证起见,假设我正在尝试使用 Kotlin Native 中的 https://linux.die.net/man/3/nftw 递归地遍历文件系统中的目录。 (我知道还有其他方法可以做到这一点,使用其他 C 函数,但这不是这个问题的核心。)

nftw() 接受一个函数作为回调:

val directory = "//some/directory"
val callback = kotlinx.cinterop.staticCFunction {
            file: CPointer<ByteVar>?,
            stat: CPointer<stat>?,
            typeFlag: Int,
            b: CPointer<FTW>? ->

            val fileName = file?.toKString()
            println(fileName)
            val result = 0
            result
        }

val depth = 10
val flags = 0
platform.posix.nftw(directory, callback, depth, flags)

这适用于通过“println()”列出文件,但是一旦 lambda 包含任何捕获的值,我就会收到以下编译器错误:

“kotlinx.cinterop.staticCFunction 必须采用未绑定的非捕获函数或 lambda”。

我的问题是:是否有任何推荐的方法关于如何 从这样的回调访问任何非全局状态?

我确实想出了一个使用全局变量的讨厌的解决方法,所以这不是我要寻找的主要内容。如果有使用@ThreadLocal 或其他东西的普遍接受的解决方案,请讨论。

【问题讨论】:

    标签: kotlin kotlin-native


    【解决方案1】:

    一般用于本机回调(不特定于nftw)。 C 函数应接受void* userData 参数并在调用时将其传递给回调。这允许您将本地数据而不是全局数据传递给回调。 即使在 C/C++ 中也是如此。

    对于这种特殊情况(无论使用何种语言),如果没有一些全局数据(或 JIT,但我们不要考虑它),真的没有办法做到这一点。因此,任何解决方法都必须是令人讨厌的。

    使用@ThreadLocal 是一种“合理的讨厌”解决方案。

    nftw 只是不是一个设计良好的 C 接口。

    【讨论】: