How do you cast a UInt64 to an Int64?

前端 未结 6 1417
我在风中等你
我在风中等你 2020-12-17 23:08

Trying to call dispatch_time in Swift is doing my head in, here\'s why:

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_mai         


        
相关标签:
6条回答
  • 2020-12-17 23:32

    simple solution for Swift 3 is an inbuilt function that takes care of overflows and buffer management.

    var a:UInt64 = 1234567890
    var b:Int64 = numericCast(a)
    
    0 讨论(0)
  • 2020-12-17 23:36

    To construct an Int64 using the bits of a UInt64, use the init seen here: https://developer.apple.com/reference/swift/int64/1538466-init

    let myInt64 = Int64(bitPattern: myUInt64)
    
    0 讨论(0)
  • 2020-12-17 23:45

    Better solution for converting:

    UInt64 Int64_2_UInt64(Int64 Value)
    {
         return (((UInt64)((UInt32)((UInt64)Value >> 32))) << 32) 
            | (UInt64)((UInt32)((UInt64)Value & 0x0ffffffff));           
    }
    
    Int64 UInt64_2_Int64(UInt64 Value)
    {
        return (Int64)((((Int64)(UInt32)((UInt64)Value >> 32)) << 32) 
           | (Int64)((UInt32)((UInt64)Value & 0x0ffffffff)));           
    }
    
    0 讨论(0)
  • 2020-12-17 23:48

    Casting a UInt64 to an Int64 is not safe since a UInt64 can have a number which is greater than Int64.max, which will result in an overflow.

    Here's a snippet for converting a UInt64 to Int64 and vice-versa:

    // Extension for 64-bit integer signed <-> unsigned conversion
    
    extension Int64 {
        var unsigned: UInt64 {
            let valuePointer = UnsafeMutablePointer<Int64>.allocate(capacity: 1)
            defer {
                valuePointer.deallocate(capacity: 1)
            }
    
            valuePointer.pointee = self
    
            return valuePointer.withMemoryRebound(to: UInt64.self, capacity: 1) { $0.pointee }
        }
    }
    
    extension UInt64 {
        var signed: Int64 {
            let valuePointer = UnsafeMutablePointer<UInt64>.allocate(capacity: 1)
            defer {
                valuePointer.deallocate(capacity: 1)
            }
    
            valuePointer.pointee = self
    
            return valuePointer.withMemoryRebound(to: Int64.self, capacity: 1) { $0.pointee }
        }
    }
    

    This simply interprets the binary data of UInt64 as an Int64, i.e. numbers greater than Int64.max will be negative because of the sign bit at the most significat bit of the 64-bit integer.

    If you just want positive integers, just get the absolute value.

    EDIT: Depending on behavior, you can either get the absolute value, or:

    if currentValue < 0 {
        return Int64.max + currentValue + 1
    } else {
        return currentValue
    }
    

    The latter option is similar to stripping the sign bit. Ex:

    // Using an 8-bit integer for simplicity
    
    // currentValue
    0b1111_1111 // If this is interpreted as Int8, this is -1.
    
    // Strip sign bit
    0b0111_1111 // As Int8, this is 127. To get this we can add Int8.max
    
    // Int8.max + currentValue + 1
    127 + (-1) + 1 = 127
    
    0 讨论(0)
  • 2020-12-17 23:48

    Try this:

    let x:UInt64 = 1000 // 1,000
    let m:Int64 = 10 * Int64(x) // 10,000
    

    or even :

    let x:UInt64 = 1000 // 1,000
    let m = 10 * Int64(x) // 10,000
    let n = Int64(10 * x) // 10,000
    let y = Int64(x) // 1,000, as Int64 (as per @Bill's question)
    

    It's not so much casting as initialising with a separate type...

    0 讨论(0)
  • 2020-12-17 23:55

    You can "cast" between different integer types by initializing a new integer with the type you want:

    let uint:UInt64 = 1234
    let int:Int64 = Int64(uint)
    

    It's probably not an issue in your particular case, but it's worth noting that different integer types have different ranges, and you can end up with out of range crashes if you try to convert between integers of different types:

    let bigUInt:UInt64 = UInt64(Int64.max) - 1      // 9,223,372,036,854,775,806
    let bigInt:Int64 = Int64(bigUInt)               // no problem
    
    let biggerUInt:UInt64 = UInt64(Int64.max) + 1   // 9,223,372,036,854,775,808
    let biggerInt:Int64 = Int64(biggerUInt)         // crash!
    

    Each integer type has .max and .min class properties that you can use for checking ranges:

    if (biggerUInt <= UInt64(Int64.max)) {
        let biggerInt:Int64 = Int64(biggerUInt)     // safe!
    }
    
    0 讨论(0)
提交回复
热议问题