在 Kotlin Native C 互操作中处理 (U)Int

Dealing with (U)Int in Kotlin Native C interop

我正在尝试将 PiGPIO library 与 Kotlin Native 一起用作链接库(不使用守护程序)。 因此,我将 C 互操作与引用 pigpio.h 文件的 .def 文件一起使用。

它可以工作(我设法使 LED 灯闪烁)但输入整数时存在问题。 虽然我没有启用实验性无符号整数功能,但生成的存根使用类型 UInt.

例如这个函数的参数:

@kotlinx.cinterop.internal.CCall public external fun gpioSetMode(gpio: kotlin.UInt, mode: kotlin.UInt): kotlin.Int { /* compiled code */ }

这对我来说没问题,因为它们在 C 中属于 unsigned 类型,我希望它尽可能的类型安全:

int gpioSetMode(unsigned gpio, unsigned mode);

现在的问题是用作函数参数的值是使用 .h 文件中的宏定义定义的。例如对于 mode 参数:

#define PI_INPUT  0
#define PI_OUTPUT 1

这些值对应的生成的Kotlin常量是Int:

类型
public const val PI_INPUT: kotlin.Int /* compiled code */
public const val PI_OUTPUT: kotlin.Int /* compiled code */

但是,尽管可以调用以常量作为参数的函数:

gpioSetMode(14, PI_OUTPUT) // compiles fine

我无法创建将模式作为参数的方法并使用它:

fun main() {
    setMode(PI_OUTPUT) // fails to compile (Type Mismatch)
}

fun setMode(mode : UInt) {
    gpioSetMode(14, mode)
}

有没有办法强制所有正整数常量为 UInt 类型?

据我所知,cinterop 工具中没有这样的选项。
事实上,可以说问题出在库头文件的 "define" 部分未使用无符号文字。但是在C中是可以省略的,所以这个header就可以了。这里的工具有点书呆子,所以它假定所有没有附加后缀的整数文字作为带符号的类型。
关于你生成的函数的工作方式。在 Kotlin 中,有一个 smart cast 的概念(参见 here),但这里有一个问题。在本文档部分,有一条关于智能转换可用性的注释,仅适用于模块内部的检查。在您的情况下,gpioSetMode(gpio, mode)PI_OUTPUT 位于同一模块中,而您的 setMode 位于另一个 one.That 中,这就是为什么第一个调用编译而第二个调用不编译的原因.
我设法在我的小样本中解决了这个问题:就像这样添加到我的代码中,重新定义常量

import my.*
const val PI_OUTPUT = my.PI_OUTPUT

其中 my 是库包,很可能 pigpio 适合您。之后,智能转换将可用于库函数以及您在此模块中声明的所有函数。