2014-11-25 13 views
18

Sto cercando un modo diretto per eseguire il cast dei bit dei valori di Int a UInt e viceversa. Per esempio (utilizzando gli 8 bit interi per semplicità) che voglio raggiungere il seguente:Int to UInt (e viceversa) bit casting in Swift

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

In un primo momento mi è venuto fuori con la seguente soluzione:

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

Ma Apple nel "unsafeBitCast() "la documentazione afferma quanto segue:

.. Attenzione :: Rompe le garanzie del sistema di tipo Swift; utilizzare con estrema cura. C'è quasi sempre un modo migliore per fare qualsiasi cosa.

Qualcuno ha la via migliore?

+0

Domanda simile qui: [Conversione firmata a unsigned in Swift] (http://stackoverflow.com/questions/25666846/converting-signed-to-unsigned-in-swift). –

+0

@ Martin sì, hai ragione. Giuro che ho cercato questo in google e stackoveflow, non è mai apparso. –

risposta

32

si può fare: esistono

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

Molti initializers simili:

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

Ho preso la via algebra. Il test è stato un problema perché è facile ottenere un overflow con la forte digitazione che interrompe l'esecuzione, PlayGround ha restituito un valore negativo dalla funzione toUInt, ha continuato a bloccarsi o ha dato errori divertenti eseguendo un doppio casting (ho aperto un bug report). In ogni caso questo è quello che ho finito con:

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 
} 

li ho provato con tutti i valori estremi (UInt.min, UInt.max, Int.min, Int.max) e quando XCode non impazzire a quanto pare lavorare, ma sembra eccessivamente complicato. abbastanza Bizarre l'UInt a Int po 'di fusione potrebbe essere raggiunto semplicemente con la proprietà hashvalue come in:

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

Ma ovviamente non è garantito per funzionare sempre (dovrebbe, ma preferisco non correre il rischio) .

Qualsiasi altra idea sarà apprezzata.

0

numericCast(...) è quello che stai cercando. È un insieme di funzioni generiche che converte da e verso diversi tipi di numeri. Scegli l'implementazione corretta in base ai tipi del suo argomento e al tipo di ritorno.

+0

Rispetto a 'UInt8 (bitpattern:)' quindi trappole 'numericCast' su under/overflow, ad esempio' lascia foo: UInt8 = numericCast (-1) 'si bloccherà. Quindi scegliere quello giusto dipende dal caso d'uso. :) –