• Swift中和C语言数据类型转换


    原文链接

    另外一个swift指针介绍不错的文章

    简介

    [UInt8]是Swift中的数组类型,也是作用比较特殊的一种数组类型, 常用于底层交互与内存操作与管理。如: 字符串编解码, 充当字节缓冲区等等

    1.字符串编解码

    • [UInt8](或[Int8])转 String
    /// "这是一个字符串" 的utf8编码
    let bytes: [UInt8] = [232, 191, 153, 230, 152, 175, 228, 184, 128, 228, 184, 170, 229, 173, 151, 231, 172, 166, 228, 184, 178]
    /// 转换成字符串
    if let msg = String(bytes: bytes, encoding: .utf8) {
    	print(msg)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • String 转 [UInt8](或[Int8])
    let msg = "这是一个字符串"
    
    if let data = msg.data(using: .utf8) {
      let bytes = [UInt8](data)
      print(bytes)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. Swift和C语言数据类型底层转换

    • 转换到C语言中的const char*, char*, void*,const void*
    C语言指针类型swift语言指针对象类型
    char *、Int *UnsafeMutablePointer
    const char *UnsafePointer
    unsigned char *UnsafeMutablePointer
    const unsigned char *UnsafePointer
    void *UnsafeMutableRawPointer
    const void *UnsafeRawPointer
    UInt8 *UnsafeMutablePointer
    • 几种特殊的指针类型
      UnsafeRawBufferPointer
      UnsafeMutableRawBufferPointer
      UnsafeBufferPointer
      UnsafeMutableBufferPointer

    这些带有Buffer的指针类型, 可以理解为对应的不带Buffer的指针类型加上了缓冲区大小, 比如:
    UnsafePointer 对应 const int *, 表示仅有地址
    那UnsafeBufferPointer对应 const int * 加 size, 表示该地址与内存大小所对应的一块缓冲区

    从[UInt8]或[Int8] 转换到 const unsigned char*或 const char *

    [UInt8] -> UnsafeRawBufferPointer -> UnsafeBufferPointer -> UnsafePointer (Int8同理)

    /// 0. 原始字节数据 8字节
    let buffer = [UInt8](repeating: 0, count: 8) 
    
    /// 1. [UInt8] -> UnsafeRawBufferPointer
    let unsafeRawBufferPointer = buffer.withUnsafeBytes { $0 } 
    
    /// 2. UnsafeRawBufferPointer -> UnsafeBufferPointer
    let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
    
    /// 3. UnsafeBufferPointer -> UnsafePointer
    let unsafePointer = unsafeBufferPointer.baseAddress
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    其中 步骤1和步骤2可以合并

    /// 0. 原始字节数据 8字节
    let buffer = [UInt8](repeating: 0, count: 8)
    
    /// 1. [UInt8] -> UnsafeBufferPointer
    let unsafeBufferPointer = buffer.withUnsafeBufferPointer {$0}
    
    /// 2.. UnsafeBufferPointer -> UnsafePointer
    let unsafePointer = unsafeBufferPointer.baseAddress
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    从[UInt8]或[Int8]转换到 unsigned char *或 char *

    [UInt8] -> UnsafeMutableRawBufferPointer -> UnsafeMutableBufferPointer -> UnsafeMutablePointer (Int8同理)

    /// 0. 原始字节数据 8字节
    var buffer = [UInt8](repeating: 0, count: 8)
    
    /// 1. [UInt8] -> UnsafeMutableRawBufferPointer
    let unsafeMutableRawBufferPointer = buffer.withUnsafeMutableBytes { $0 }
    
    /// 2. UnsafeMutableRawBufferPointer -> UnsafeMutableBufferPointer
    let unsafeMutableBufferPointer = unsafeMutableRawBufferPointer.bindMemory(to: UInt8.self)
    
    /// 3. UnsafeMutableBufferPointer -> UnsafeMutablePointer
    let unsafeMutablePointer = unsafeMutableBufferPointer.baseAddress
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中的步骤1和步骤2也是可以合并的

    /// [UInt8] -> UnsafeMutableBufferPointer
    let unsafeMutableBufferPointer = buffer.withUnsafeMutableBufferPointer {$0 }
    
    • 1
    • 2
    • 从[UInt8]或[Int8]转换成const void *或者void *
      在上述的步骤里, 在步骤1得到的unsafeMutableRawBufferPointer就可以通过该对象的baseAddress字段就能获取到对应的void *
    /// 获取 const void *
    let unsafeRawPointer = unsafeRawBufferPointer.baseAddress
    
    /// 获取void *
    let unsafeMutableRawPointer = unsafeMutableRawBufferPointer.baseAddress
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 从C语言中的const char * , char *, const unsigned char *, unsigned char *, const void *, void *对应缓冲区的数据创建 Data

    /// 这里是示例, 类型为 UnsafeMutablePointer, 也就是 char *
    /// message可能来自任何C语言的接口
    let message = strerror(errno) 
    
    /// 通过指针和大小来构造 UnsafeBufferPointer
    let unsafeBufferPointer = UnsafeBufferPointer(start: message, count: strlen(msg!))
    
    /// 构造Data
    let data = Data(buffer: unsafeBufferPointer)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3. 从Data得到 [UInt8] 或者 [Int8]以及String

    • Data其实内部就是[UInt8],在大部分情况下都可以直接当成[UInt8]来使用, 字节的append,remove, insert, find等等都有相同的操作
    • 但是如果需要拷贝出来一份 [UInt8]或者[Int8],可以使用map函数
    /// 缓冲区里的数据    
    let data = Data(buffer: unsafeBufferPointer)
    
    /// [UInt8]
    let u8a = data.map {$0}
    
    /// [Int8]
    let s8a = data.map {Int8($0)}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • String也自带从data数据的构造函数
    let text = String(data: data, encoding: .utf8)
    
    • 1

    数据类型转换方法

        // 将int转化为UInt8
        public static func toUInt(signed: Int) -> UInt {
            let unsigned = signed >= 0
                           ? UInt(signed)
                           : UInt(signed  - Int.min) + UInt(Int.max) + 1
            
            return unsigned
        }
        
        // 将UInt8 转化为 int
        public static func convertToInt(unsigned: UInt) -> Int {
            
            let signed = (unsigned <= UInt(Int.max))
                        ? Int(unsigned)
                        : Int(unsigned - UInt(Int.max) - 1) + Int.min
            
            return signed
        }
        
        //4bytes转Int
        public static func convert4BytesToInt(data: Data) -> Int {
            var value : UInt32 = 0
            let data = NSData(bytes: [UInt8](data), length: data.count)
            data.getBytes(&value, length: data.count)
            value = UInt32(bigEndian: value)
            return Int(value)
        }
        
        // MARK:- int 转成 4字节的bytes
        public static func convertIntTo4Bytes(value: Int) -> [UInt8] {
            if value < 0 || value > 65535 {
                return [UInt8]()
            }
            let UInt = UInt32.init(Double.init(value))
            return [UInt8(truncatingIfNeeded: UInt >> 24),
                    UInt8(truncatingIfNeeded: UInt >> 16),
                    UInt8(truncatingIfNeeded: UInt >> 8),
                    UInt8(truncatingIfNeeded: UInt)]
        }
        
        
        /// UInt 16 转[UInt8]
        public static func convertUInt16To2Bytes(value: UInt16) -> [UInt8] {
            return [UInt8(truncatingIfNeeded: value >> 8), UInt8(truncatingIfNeeded: value)]
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    Mac电脑专业音乐制作Logic Pro X中文
    数组的API
    LeetCode 768. 最多能完成排序的块 II
    设计模式是测试模式咩?
    一个高性能类型安全的.NET枚举实用开源库
    SpringCloudGateway--Sentinel限流、熔断降级
    【已解决】‘CV_LOAD_IMAGE_GRAYSCALE’ was not declared in this scope
    点赞量上三千了
    Java数组编程练习题(面试题)
    imx6ull内置温度传感器实践1:输出一个采样
  • 原文地址:https://blog.csdn.net/JH_Cao/article/details/127657927