Swift 3.0中C语言指针类型在Swift编程语言中如何操作

Swift 3.0在2.0基础上做了许多改动,其中之一就是与C API的兼容性上。这里我将主要讲解一下C语言的指针与Swift编程语言的桥接在Swift 3.0中改成啥样了。


首先,为了Swift编程语言语法体系的统一性,Swift语言核心设计团队为所有诸如UnsafePointer、UnsafeMutablePointer等类型增加了Optional,这个在Swift 2.x中是没有的,不过你可以直接对一个UnsafePointer<Int32>类型的对象置空。而在3.0版本中增加了这些类型的Optional属性之后,我们就可以把它们作为其他类型一样去对待了。

然后,Swift 3.0给void*const void*分别引入了UnsafeRawPointer类型和UnsafeMutableRawPointer类型。而在Swift 2.x中,它们分别对应的是UnsafePointer<Void>与UnsafeMutablePointer<Void>。此外,UnsafeRawPointer类型与UnsafeMutableRawPointer类型不能直接通过UnsafePointer与UnsafeMutablePointer的构造器转换为相应类型,而只能通过它们的assumingMemoryBound(to:)方法去转。

最后,UnsafePointer类型要转为UnsafeMutablePointer类型时现在必须使用UnsafeMutablePointer的init(mutating:)方法,这里增加了一个参数标签mutating。


下面我们将通过一段代码来呈现以上说的这三点。以下有3个代码片段,分别是一个头文件、一个C源文件和一个Swift源文件。

头文件内容:

extern void* _Nonnull GenerateData(void);
extern void UseData(const int* _Nonnull pData);

extern const void* _Nullable GenerateData2(void);
extern void UseData2(int* _Nullable pData);

C源文件内容:

#include <stdio.h>

static int sData = 10;

void* GenerateData(void)
{
    return &sData;
}

void UseData(const int *pData)
{
    printf("The data is: %d\n", *pData);
}

const void* _Nullable GenerateData2(void)
{
    return &sData;
}

void UseData2(int *pData)
{
    if(pData != NULL)
        printf("The data is: %d\n", pData[0]);
}


Swift源文件内容:

class ViewController: NSViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let dataPtr = GenerateData()
        
        // 这里可以看到,dataPtr的类型是UnsafeMutableRawPointer
        print("dataPtr type is: \(type(of: dataPtr))")
        
        // 这里先将dataPtr类型转换为UnsafeMutablePointer<Int32>类型
        let dataInt32Ptr = dataPtr.assumingMemoryBound(to: type(of: Int32()))
        
        print("dataInt32Ptr type is: \(type(of: dataInt32Ptr))")
        
        // 我们还可以对指针所指向的整型数据做些修改
        dataInt32Ptr.pointee += 10
        
        // 在传递UseData的实参时,需要将dataInt32Ptr的类型再转为UnsafePointer<Int32>
        UseData(UnsafePointer<Int32>(dataInt32Ptr))
        
        // 这里dataPtr2是UnsafeRawPointer?类型
        let dataPtr2 = GenerateData2()
        
        // 这里dataInt32Ptr2的类型是UnsafePointer<Int32>?
        let dataInt32Ptr2 = dataPtr2?.assumingMemoryBound(to: type(of: Int32()))
        
        // 这里需要将dataInt32Ptr2类型转换为UnsafeMutablePointer<Int32>
        UseData2(UnsafeMutablePointer<Int32>(mutating: dataInt32Ptr2))
        
        var intObj: Int32 = 0
        
        // 这里可以看到,在Swift中的一个Int32类型对象,
        // 对它取地址操作也可以与UnsafePointer<Int32>类型进行匹配
        UseData(&intObj)
        
        UseData2(&intObj)
        
        var uintObj: UInt = 1
        
        // 如果要将一个UnsafePointer<UInt>转换为UnsafePointer<Int32>,
        // 现在无法直接用UnsafePointer的构造方法进行转换。
        // 为了看清整个转换过程,我们先用withUnsafePointer来获取uintObj的指针类型对象
        let uintPtr = withUnsafePointer(to: &uintObj) {
            (ptr: UnsafePointer<UInt>) -> UnsafePointer<UInt> in
            return ptr
        }
        
        // 这里使用了Swift 3新引入的UnsafePointer与UnsafeMutablePointer的
        // withMemoryRebound(to:capacity:_:)方法显式地将当前指针的原始类型
        // 转换为目标类型的指针对象。
        // 这里的Int32.self相当于type(of: Int32()),获取到的是Int32元类型
        UseData(uintPtr.withMemoryRebound(to: Int32.self, capacity: 1) {
            (ptr: UnsafePointer<Int32>) -> UnsafePointer<Int32> in
            return ptr
        })
        
        // 为了看清下一步操作,我们这里将withMemoryRebound方法所返回的
        // UnsafePointer<Int32>对象hold住
        let constPtr = uintPtr.withMemoryRebound(to: Int32.self, capacity: 1) {
            (ptr: UnsafePointer<Int32>) -> UnsafePointer<Int32> in
            return ptr
        }
    }
}

上述代码详细介绍了如何通过C语言函数接口获得一个指针类型,然后做相互转换。此外,还有在Swift中定义的对象如何作为指针类型的参数传入C语言函数中。这里涉及到了Swift 3.0中的新方法,包括UnsafeRawPointer与UnsafeMutableRawPointer的assumingMemoryBound(to:)方法;UnsafePointer与UnsafeMutablePointer的withMemoryRebound(to:capacity:_:)方法。Swift 3.0中取消了UnsafePointer与UnsafeMutablePointer构造方法对任意类型的指针进行转换的实现,取而代之的是,对于指针转换的数据类型都一致的情况,可以通过UnsafeMutablePointer中的init(mutating:)方法将UnsafePointer转换UnsafeMutablePointer;而UnsafePointer可直接使用init(_:)将UnsafeMutablePointer转换相应类型的UnsafePointer类型。除此之外,非相应数据类型的指针转换都必须使用withMemoryRebound(to:capacity:_:)方法。

各位可以在Xcode 8上尝试运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值