在 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
适合您。之后,智能转换将可用于库函数以及您在此模块中声明的所有函数。
我正在尝试将 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
适合您。之后,智能转换将可用于库函数以及您在此模块中声明的所有函数。