首页 > 其他分享 >Swift中指针UnsafePointer的常见用法

Swift中指针UnsafePointer的常见用法

时间:2023-08-23 19:11:06浏览次数:35  
标签:UnsafeMutablePointer UnsafePointer 类型 let print Swift 指针

指针类型

//基本指针
UnsafePointer<T>                    const T *
UnsafeMutablePointer                T *
//集合指针
UnsafeBufferPointer                 const T * //指向一个连续已知类型区域,可以看成一个集合,并支持集合操作
UnsafeMutableBufferPointer          T * //指向一个连续已知类型区域,可以看成一个集合,并支持集合操作
//空指针
UnsafeRawPointer                    const void *
UnsafeMutableRawPointer             void *
UnsafeRawBufferPointer              const void * //指向一个连续未知类型区域
UnsafeMutableRawBufferPointer       void *  //指向一个连续未知类型区域

 

UnsafePointer 和 UnsafeMutablePointer UnsafePointer只读指针 UnsafeMutablePointer可修改指针
UnsafePointer只读指针 通过UnsafePointer<T>定义一个类型为T的指针,通过pointee成员即可获得T的值。
//UnsafePointer参数只能接收inout修饰的类型,而inout修饰的类型必然是可写的,所以参数只能用var定义
func call(_ p: UnsafePointer<Int>) {
    print("\(p.pointee)")
}
var a = 1234
//&a用于传递指针
call(&a) // 打印:1234
UnsafeMutablePointer可修改指针 可以通过设置p.pointee 修改指针的值。
func modify(_ p: UnsafeMutablePointer<Int>) {
    p.pointee = 5678
}
var a = 1234
modify(&a)
print("\(a)") // 打印:5678
UnsafeBufferPointer 集合指针类型 UnsafeBufferPointer指针实现了Collection协议,因此可以直接使用Collection中的各种方法来遍历操作数据,filter,map...等。 Swift的数组提供了函数withUnsafeBufferPointer,通过它我们可以方便的用指针来处理数组。 下面通过withUnsafeBufferPointer获得变量p,p的类型为UnsafeBufferPointer<Int32>,它代表着一整块的连续内存,它是集合类型指针,并且它也支持大部分数组操作。
let a: [Int32] = [1, 2, -1, -2, 5, 6]
let p = a.withUnsafeBufferPointer { $0 }
print("\(p.count)") // 打印:6
print("\(p[3])") // 打印:-2
空指针:UnsafeRawPointer 就像C语言有void*(即空指针)一样,Swift也有自己的空指针,它通过类型UnsafeRawPointer来获得
let rp: UnsafeMutablePointer<CChar> = rRes.value
let strLength = rRes.length
//将UnsafeMutablePointer<CChar> C语言的char *指针转成 UnsafeMutableRawPointer 的void *任意指针。然后直接取出封装成String字符串
let strRes = String.init(bytesNoCopy: UnsafeMutableRawPointer(mutating: rp), length: Int(strLength), encoding: .utf8, freeWhenDone: false) 
指针的类型转换
UnsafePointer 基本指针
//将指针的类型转换成一个临时的给定类型,并将指针传递给closure
func withMemoryRebound<T, Result>(to: T.Type, capacity: Int, (UnsafePointer<T>) -> Result) -> Result
//向下移动一位,并返回一个新的指针 
func successor() -> UnsafePointer<Pointee>
//向上移动一位,并返回一个新的指针
func predecessor() -> UnsafePointer<Pointee>

RawPointer 空指针
//转换给指定类型的指针
func assumingMemoryBound<T>(to: T.Type) -> UnsafeMutablePointer<T>
//转换成指定类型的指针,capacity指定了这个指针读取的T数据数量
func bindMemory<T>(to type: T.Type, capacity count: Int) -> UnsafeMutablePointer<T>

UnsafeBufferPointer 集合指针
let rpSub:UnsafeMutablePointer<UInt8> = rp.withMemoryRebound(to: UInt8.self, capacity: Int(strLength), { $0 })
let buffer = UnsafeBufferPointer<UInt8>.init(start: rpSub, count: Int(strLength))

 

指针的操作 指针的辅助函数,通过函数withUnsafePointer,获得指定类型的对应指针
//返回一个T类型指针。将第一个参数T以指针的形式传递给closure
func withUnsafePointer<T, Result>(to: T, (UnsafePointer<T>) -> Result) -> Result
func withUnsafePointer<T, Result>(to: inout T, (UnsafePointer<T>) -> Result) -> Result
func withUnsafeMutablePointer<T, Result>(to: inout T, (UnsafeMutablePointer<T>) -> Result) -> Result
func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
定义一个整形a,而p就是指向a的整形指针,它的类型会被自动转换为UnsafePointer<Int>, 第二个参数被简化为了{ $0 },代码块接收一个UnsafePointer<Int>参数,该参数即是a的地址,直接通过$0将它返回,即得到了a的指针,最终它被传给了p。
var a = 1234
let p = withUnsafePointer(to: &a) { $0 }
print("\(p.pointee)") // 打印:1234
获取指针并进行字节级操作 withUnsafeBytes 如果要对某块内存进行字节级编程。可以通过withUnsafeBytes得到某个类型的数据的字节指针,从而可以对它们进行字节级编程。 因为withUnsafeBytes返回了一个类型UnsafeRawBufferPointer,该类型代表着一个字节级的内存块集合指针,所以以通过下标索引、for循环的方式来处理返回的对象。
var a: UInt32 = 0x12345678
let p = withUnsafeBytes(of: &a) { $0 }
var log = ""
for item in p {
    let hex = NSString(format: "%x", item)
    log += "\(hex)"
}
print("\(p.count)") // 打印:4
print("\(log)") // 对于小端机器会打印:78563412

 

通过指针动态创建、销毁内存 使用Swift可以直接操作内存,如可以开辟和管理一块内存,最后释放它,Swift提供了UnsafeMutablePointer的成员函数allocate来处理该工作。
let p = UnsafeMutablePointer<Int32>.allocate(capacity: 1)
p.initialize(to: 0) // 初始化
p.pointee = 32
print("\(p.pointee)") // 打印:32
p.deinitialize(count: 1) // 反初始化
p.deallocate()
C标准库函数的映射调用 Swift提供了大量的C标准库的桥接方法,我们可以像调用C语言库函数一样它们,如memcpy,strcpy等。
var n = 10086
// malloc
let p = malloc(MemoryLayout<Int32>.size)!
// memcpy
memcpy(p, &n, MemoryLayout<Int32>.size)
let p2 = p.assumingMemoryBound(to: Int32.self)
print("\(p2.pointee)") // 打印:10086
// strcpy
let str = "abc".cString(using: .ascii)!
if str.count != MemoryLayout<Int32>.size {
    return
}
let pstr = p.assumingMemoryBound(to: CChar.self)
strcpy(pstr, str)
print("\(String(cString: pstr))") // 打印:abc
// strlen
print("\(strlen(pstr))") // 打印: 3
// memset
memset(p, 0, MemoryLayout<Int32>.size)
print("\(p2.pointee)") // 打印:0
// strcat
strcat(pstr, "h".cString(using: .ascii)!)
strcat(pstr, "i".cString(using: .ascii)!)
print("\(String(cString: pstr))") // 打印:hi
// strstr
let s = strstr(pstr, "i")!
print("\(String(cString: s))") // 打印:i
// strcmp
print("\(strcmp(pstr, "hi".cString(using: .ascii)!))") // 打印:0
// free
free(p)

 

实际使用案例 1.将C函数库返回的char *指针,读取成字符串
let rRes = c_shmread()

let rp: UnsafeMutablePointer<CChar> = rRes.value
let strLength = rRes.length

//1.先将UnsafeMutablePointer<CChar> C语言的char *指针转成 UnsafeMutableRawPointer 的void *任意指针。然后直接取出封装成String字符串
if let strRes = String.init(bytesNoCopy: UnsafeMutableRawPointer(mutating: rp), length: Int(strLength), encoding: .utf8, freeWhenDone: false) {
    return strRes
} else {
    return ""
}

//2.使用withMemoryRebound转换指针类型从CChar转成UInt8类型;
let rpSub:UnsafeMutablePointer<UInt8> = rp.withMemoryRebound(to: UInt8.self, capacity: Int(strLength), { $0 })
//然后创建集合类型指针UnsafeBufferPointer;
let buffer = UnsafeBufferPointer<UInt8>.init(start: rpSub, count: Int(strLength))
buffer.forEach {
    print($0)
}
//然后创建Data, 再将data转成String
let data = Data(bytes: rpSub, count: Int(strLength))
let str = String(data: data, encoding: String.Encoding.utf8)
        

 


参考文章: https://juejin.cn/post/7030789069915291661#heading-6 https://www.jianshu.com/p/a9956ee1ab61    

标签:UnsafeMutablePointer,UnsafePointer,类型,let,print,Swift,指针
From: https://www.cnblogs.com/zhou--fei/p/17652559.html

相关文章

  • 类和对象(c++对象模型和this指针)
    1.成员变量和成员函数分开储存只有非静态成员变量才属于类的对象上。空对象内存占用空间为1this指针的概念this指针指向被调用的成员函数所属的对象this指针式隐含每个非静态成员函数内的一种指针。this指针不需要定义,直接使用即可。this指针的用途:1.当形参和成员变量同名时,可用thi......
  • iOS开发Swift-字符串与字符
    1.字符串的定义letsomeString="somestringvalue"2.多行字符串的定义(""")letquotation="""有一个人前来买瓜。"这瓜甜吗?"他问。""" 前一个"""前和后一个"""后无换行//前一个"""前和后一个......
  • iOS开发Swift-基本运算符
    1.一元、二元、三元运算符一元单一操作对象-a   !b   c!二元两个操作对象2+3三元三目运算符a?b:c2.赋值运算符(=)leta=10varb=5b=alet(x,y)=(1,2)赋值运算符不返回任何值,所以ifx=y{...}无效。3.算术运算符+  -......
  • Swift-基础语法之变量&常量&元组
    使用 let来声明一个常量,用 var来声明一个变量。常量的值在编译时并不要求已知,但是你必须为其赋值一次。这意味着你可以使用常量来给一个值命名,然后一次定义多次使用varmyVariable=42myVariable=50letmyConstant=42常量或者变量必须拥有和你赋给它们的值相同的类型。不......
  • swift学习笔记之控制流
    控制流:1、if语句letcount=5ifcount>=3{print("yes")}else{print("no")}2、switch语句(1)Swift中不需要在case块中显示地使用break跳出switch。如果想要实现C风格的落入特性,可以给需要的case分支插入fallthrough语句letfruit="apple"switchfruit{case"a......
  • swift学习笔记之---数组、字典、枚举、结构体
    1、数组-Arraylettypes=["none","warning","error"]//省略类型的数组声明letmenbers=[String]()//声明一个空数组menbers.append("six")//添加元素menbers+=["seven"]//添加元素menbers.insert("one"......
  • Swift - 基本数据类型,及常/变量声明
    用oc编码已经有段时间了,这期间一直在使用oc和学习oc的编码技巧,忽闻小伙伴说:swift已经是趋势了,有时间多看看吧所以我也开始从网上搜索博客,感谢hangge.com的博客,如有冒犯之处,请多见谅,因为是看着大神的博客开始swif全面的学习之路!方向已定,无论前面有多难,都要走下去! 一、swift中基本的......
  • Swift - 使用arc4random()、arc4random_uniform()取得随机数
    arc4random()这个全局函数会生成9位数的随机整数1,下面是使用arc4random函数求一个1~100的随机数(包括1和100)lettemp:Int=Int(arc4random()%100)+1print(temp)2,下面是使用arc4random_uniform函数求一个1~100的随机数(包括1和100)lettemps:Int=Int(arc4random_uniform(10......
  • Swift - 区间运算符(... 和 ..<)
    区间运算符可以用来表示两个操作数之间的范围集合1,闭区间运算符:a...bforicountin512...1024{print(icount)//从512遍历到1024(包括1024)}2,半闭区间运算符:a..<betfruts=["apple","orange","banana"]leticount=fruts.countforii......
  • Leetcode 两个队列实现栈 swift
    queue1 是最后生成的栈queue2是临时队列,把新进来的先放进去,再把queue1里的数据从头到尾读进去,然后互换classMyStack{varqueue1:[Int]=[]varqueue2:[Int]=[]init(){}funcpush(_x:Int){queue2.append(x)whil......