如何使用Swift返回UnsafePointer <cchar>和UnsafePointer <cunsignedint>

时间:2015-04-27 19:28:28

标签: c swift callback type-conversion

我正在编写一个需要与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";

你能帮助我吗?

1 个答案:

答案 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次出现都是指针转换。在字符串案例中,因为utf8UInt8,但CCharInt8的别名。在数组的情况下,因为你想要一个指向第一个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)