2014-11-25 7 views
18

Ich bin auf der Suche nach einem direkten Weg, um die Bit-Werte eines Int in UInt und umgekehrt umzuwandeln. Zum Beispiel (unter Verwendung der 8-Bit-Integer der Einfachheit halber) ich folgendes erreichen will:Int zu UInt (und umgekehrt) Bit Casting in Swift

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

Zuerst habe ich kam mit folgender Lösung:

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

Aber Apple in der „unsafeBitCast() "Dokumentation besagt Folgendes:

.. Vorsicht :: Bricht die Garantien von Swift Typ System; Verwenden Sie mit extreme Vorsicht. Es gibt fast immer einen besseren Weg, etwas zu tun.

Hat jemand den besseren Weg?

+0

Ähnliche Frage hier: [Konvertieren von signed in unsigned in Swift] (http://stackoverflow.com/questions/25666846/converting-signed-to-unsigned-in-swift). –

+0

@Martin ja, du hast recht. Ich schwöre, ich habe sowohl in Google als auch in Stackoveflow nach diesem gesucht, es erschien nie. –

Antwort

32

können Sie tun:

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

Viele ähnliche initializers existieren:

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) 
} 
2

Ich nahm die Algebra-Route. Das Testen war sehr mühsam, da es leicht ist, einen Overflow zu bekommen, da die Ausführung die Ausführung stark unterbricht, PlayGround einen negativen Wert von der toUInt-Funktion liefert, immer wieder abstürzt oder witzige Fehler macht (ich habe einen Fehlerbericht geöffnet). Wie auch immer das ist, was ich am Ende mit:

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 
} 

ich sie mit allen Extremwerten getestet (UInt.min, UInt.max, Int.min, Int.max) und wenn XCode nicht verrückt geht es scheint zu arbeiten, aber es sieht übermäßig kompliziert aus.

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

Aber offensichtlich ist es nicht garantiert immer funktionieren (es sollte, aber ich möchte lieber nicht nehmen die Chance): Bizarre genug die UInt zu Int Bit Casting einfach mit dem Hashwert Eigenschaft wie in erreicht werden könnte .

Jede andere Idee wird geschätzt.

0

numericCast(...) ist das, was Sie suchen. Es ist eine Reihe von generischen Funktionen, die von und zu verschiedenen Zahlentypen konvertiert. Es wählt die richtige Implementierung basierend auf den Typen seines Arguments und des Rückgabetyps aus.

+0

Im Vergleich zu 'UInt8 (bitpattern:)' wird dann 'numericCast' auf Unter/Überlauf abgefangen, z. B.' let foo: UInt8 = numericCast (-1) 'stürzt ab. Die Wahl des richtigen hängt also vom Anwendungsfall ab. :) –