我正在编写一个需要与C库互操作的Swift程序。 此C库由一组使用回调的函数组成。 我解决了如何将Swift函数传递给这些C函数的问题,但是我很难将Swift本机类型转换为适当的C类型。
具体来说,我有这两个回调(签名必须是这个才能被C库接受):
func peer_name_handler_swift_test(p: peer_wr) -> UnsafePointer<CChar>
{
return nil;
}
func peer_ver_handler_swift_test(p: peer_wr) -> UnsafePointer<CUnsignedInt>
{
return nil;
}
好吧,尽管我付出了努力,但我无法从String Swift类型和简单的CUnsignedInt数组中返回正确的类型。
我想在这些回调中返回的2个数据是这些:
var BLZ_SWIFT_TEST_PEER_VER: [CUnsignedInt] = [0,0,1,0];
var BLZ_SWIFT_TEST_PEER_NAME: String = "test_swift_peer";
你能帮助我吗?
答案 0 :(得分:1)
可以通过各种方式将数据强制转换为正确的指针类型。这个问题的棘手部分是决定如何管理你给出指针的内存。
如果要在编译时声明静态值,可以这样做:
// I _think_ you need to manually null-terminate the string here
let BLZ_SWIFT_TEST_PEER_NAME: StaticString = "test_swift_peer\0"
func peer_name_handler_swift_test(p: peer_wr) -> UnsafePointer<CChar>
{
return UnsafePointer(BLZ_SWIFT_TEST_PEER_NAME.utf8Start)
}
// tuples are the closest approximation to C fixed-size arrays
var BLZ_SWIFT_TEST_PEER_VER
= (0,0,1,0) as (CUnsignedInt,CUnsignedInt,CUnsignedInt,CUnsignedInt)
func peer_ver_handler_swift_test(p: peer_wr) -> UnsafePointer<CUnsignedInt>
{
return withUnsafePointer(&BLZ_SWIFT_TEST_PEER_VER) {
UnsafePointer($0)
}
}
两个函数体中的额外UnsafePointer
次出现都是指针转换。在字符串案例中,因为utf8
是UInt8
,但CChar
是Int8
的别名。在数组的情况下,因为你想要一个指向第一个CUnsignedInt
的指针,而不是一个指向4元组的指针。
如果你想在运行时更改值,你需要决定谁将创建/释放内存,是否需要分配多个内存位,因为回调的调用者将存储指针然后如果你改变它,你将需要分配一个新的内存而不是覆盖你已经发出的内存等,如果是这样,你如何跟踪它以便以后释放它以避免泄漏。如果你想要一个静态字符串,但想要在运行时创建一个静态字符串,比如从配置文件中创建,你可以这样做:
// prior to the callback getting called
let namePtr = strdup(BLZ_SWIFT_TEST_PEER_NAME)
func peer_name_handler_swift_test(p: peer_wr) -> UnsafePointer<CChar>
{
return UnsafePointer(namePtr)
}
// then some time later, if you want to clean up
free(namePtr)