【问题标题】:Int to UInt (and vice versa) bit casting in SwiftSwift 中的 Int 到 UInt(反之亦然)位转换
【发布时间】:2015-01-23 11:32:20
【问题描述】:

我正在寻找一种将 Int 的位值位转换为 UInt 的直接方法,反之亦然。例如(为简单起见,使用 8 位整数)我想实现以下目标:

let unsigned: UInt8 = toUInt8(-1)  // unsigned is 255 or 0xff
let signed:   Int8  = toInt8(0xff) // signed is -1 

起初我提出了以下解决方案:

let unsigned = unsafeBitCast(Int8(-1), UInt8.self)
let signed   = unsafeBitCast(UInt8(0xff), Int8.self)

但苹果在“unsafeBitCast()”文档中声明如下:

.. 注意:: 破坏了 Swift 类型系统的保证;与 极度关心。几乎总是有更好的方法来做任何事情。

谁有更好的方法?

【问题讨论】:

标签: ios macos swift casting binary


【解决方案1】:

numericCast(...) 是您正在寻找的。它是一组通用函数,可以在不同的数字类型之间进行转换。它根据参数的类型和返回类型选择正确的实现。

【讨论】:

  • UInt8(bitpattern:) 相比,numericCast 会陷入下溢/溢出,例如,let foo: UInt8 = numericCast(-1) 会崩溃。所以选择正确的取决于用例。 :)
【解决方案2】:

我选择了代数路线。测试一直很痛苦,因为强类型破坏执行很容易溢出,PlayGround 从 toUInt 函数返回一个负值,它不断崩溃或在进行双重转换时出现有趣的错误(我打开了一个错误报告)。无论如何,这就是我最终的结果:

func toUint(signed: Int) -> UInt {

    let unsigned = signed >= 0 ?
        UInt(signed) :
        UInt(signed  - Int.min) + UInt(Int.max) + 1

    return unsigned
}

func toInt(unsigned: UInt) -> Int {

    let signed = (unsigned <= UInt(Int.max)) ?
        Int(unsigned) :
        Int(unsigned - UInt(Int.max) - 1) + Int.min

    return signed
}

我用所有极端值(UInt.min、UInt.max、Int.min、Int.max)对它们进行了测试,当 XCode 没有发疯时,它似乎可以工作,但它看起来过于复杂。奇怪的是,UInt 到 Int 的位转换可以通过 hashvalue 属性简单地实现,如下所示:

signed = UInt.max.hashValue // signed is -1

但显然它不能保证总是有效(它应该,但我宁愿不冒险)。

任何其他想法将不胜感激。

【讨论】:

    【解决方案3】:

    你可以这样做:

    let unsigned = UInt8(bitPattern: Int8(-1)) // -> 255
    let signed   = Int8(bitPattern: UInt8(0xff)) // -> -1
    

    存在许多类似的初始化器:

    extension Int8 {
        init(_ v: UInt8)
        init(_ v: UInt16)
        init(truncatingBitPattern: UInt16)
        init(_ v: Int16)
        init(truncatingBitPattern: Int16)
        init(_ v: UInt32)
        init(truncatingBitPattern: UInt32)
        init(_ v: Int32)
        init(truncatingBitPattern: Int32)
        init(_ v: UInt64)
        init(truncatingBitPattern: UInt64)
        init(_ v: Int64)
        init(truncatingBitPattern: Int64)
        init(_ v: UInt)
        init(truncatingBitPattern: UInt)
        init(_ v: Int)
        init(truncatingBitPattern: Int)
        init(bitPattern: UInt8)
    }
    

    【讨论】:

      猜你喜欢
      • 2016-12-05
      • 1970-01-01
      • 2020-10-24
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多