2014-07-09 18 views
40

Per integrarsi con le API C durante l'utilizzo di Swift, ho bisogno di utilizzare la funzione sizeof. In C, questo è stato facile. In Swift, sono in un labirinto di errori di battitura.Swift: come usare sizeof?

ho questo codice:

var anInt: Int = 5 
var anIntSize: Int = sizeof(anInt) 

La seconda linea è l'errore " 'NSNumber' non è un sottotipo di 'T.Type'". Perché è questo e come lo risolvo?

risposta

42

Usa sizeof come segue:

let size = sizeof(Int) 

sizeof utilizza il tipo come parametro.

Se si desidera la dimensione della variabile anInt, è possibile passare il campo dynamicType a sizeof.

Come così:

var anInt: Int = 5 
var anIntSize: Int = sizeof(anInt.dynamicType) 

O più semplicemente (sottolineato da user102008):

var anInt: Int = 5 
var anIntSize: Int = sizeofValue(anInt) 
+7

o 'let anIntSize = sizeofValue (anInt)' – user102008

73

aggiornato per Swift 3

stare attenti che MemoryLayout<T>.size significa qualcosa di diverso rispetto sizeof in C/Obj-C. È possibile leggere questo thread precedente https://devforums.apple.com/message/1086617#1086617

Swift utilizza un tipo generico per rendere esplicito che il numero è noto al momento della compilazione.

Per riepilogare, MemoryLayout<Type>.size è lo spazio richiesto per una singola istanza mentre MemoryLayout<Type>.stride è la distanza tra gli elementi successivi in ​​una matrice contigua. MemoryLayout<Type>.stride in Swift è lo stesso di sizeof(type) in C/Obj-C.

Per dare un esempio più concreto:

struct Foo { 
    let x: Int 
    let y: Bool 
} 

MemoryLayout<Int>.size  // returns 8 on 64-bit 
MemoryLayout<Bool>.size  // returns 1 
MemoryLayout<Foo>.size  // returns 9 
MemoryLayout<Foo>.stride // returns 16 because of alignment requirements 
MemoryLayout<Foo>.alignment // returns 8, addresses must be multiples of 8 
+0

Wow, questo è un cambiamento piuttosto serio rispetto a quanto è stato utilizzato. Ha portato ad alcuni bug quando il nostro team è passato a Swift 3. –

+0

non riesco a trovare MemoryLayout in swift 2.3 –

12

In Xcode 8 con Swift 3 beta 6 non v'è alcuna funzione sizeof(). Ma se vuoi, puoi definirne uno per le tue esigenze. Questa nuova funzione sizeof funziona come previsto con un array. Questo non era possibile con la vecchia funzione sizeof integrata.

let bb: UInt8 = 1 
let dd: Double = 1.23456 

func sizeof <T> (_ : T.Type) -> Int 
{ 
    return (MemoryLayout<T>.size) 
} 

func sizeof <T> (_ : T) -> Int 
{ 
    return (MemoryLayout<T>.size) 
} 

func sizeof <T> (_ value : [T]) -> Int 
{ 
    return (MemoryLayout<T>.size * value.count) 
} 

sizeof(UInt8.self) // 1 
sizeof(Bool.self) // 1 
sizeof(Double.self) // 8 
sizeof(dd)   // 8 
sizeof(bb)   // 1 

var testArray: [Int32] = [1,2,3,4] 
var arrayLength = sizeof(testArray) // 16 

avete bisogno di tutte le versioni della funzione sizeof, per ottenere la dimensione di una variabile e per ottenere la dimensione corretta di un tipo di dati e di un array.

Se si definisce solo la seconda funzione, quindi sizeof (UInt8.self) e sizeof (Bool.self) risulteranno in "8". Se definisci solo le prime due funzioni, sizeof (testArray) risulterà in "8".

+0

Come ho capito, la funzione sizeof restituisce la dimensione di un oggetto, in byte. Destra? Quindi, perché restituisce "24", quando fornisco la seguente stringa come parametro? "11111111111" –

+0

Questo è il motivo per cui le stringhe dinamiche vengono decodificate in Swift Unicode –

+0

Anche se funzionerà per tipi incorporati, penso che il metodo sizeof array abbia un valore limitato. Vedi la discussione sulla dimensione e lo stride sopra. Una serie di strutture arbitrarie ha spesso requisiti di allineamento speciali che renderanno il numero effettivo di byte contigui salvati più grande. –

11

Swift 3 ora ha MemoryLayout.size(ofValue:) che può cercare le dimensioni dinamicamente.

L'utilizzo di una funzione generica che a sua volta utilizza MemoryLayout<Type> avrà risultati imprevisti se ad es. passargli un riferimento di tipo protocollo. Questo perché, per quanto ne so, il compilatore ha tutte le informazioni sul tipo di cui ha bisogno per riempire i valori al momento della compilazione, il che non è evidente quando si guarda alla chiamata della funzione.

2

Swift 4

Da Xcode 9 in poi v'è ora una proprietà denominata .bitWidth, questo fornisce un altro modo di scrivere sizeof: funzioni per istanze e tipi interi:

func sizeof<T:FixedWidthInteger>(_ int:T) -> Int { 
    return int.bitWidth/UInt8.bitWidth 
} 

func sizeof<T:FixedWidthInteger>(_ intType:T.Type) -> Int { 
    return intType.bitWidth/UInt8.bitWidth 
} 

sizeof(UInt16.self) // 2 
sizeof(20) // 8 

Ma sarebbe più senso per coerenza per sostituire sizeof: con .byteWidth:

extension FixedWidthInteger { 
    var byteWidth:Int { 
     return self.bitWidth/UInt8.bitWidth 
    } 
    static var byteWidth:Int { 
     return Self.bitWidth/UInt8.bitWidth 
    } 
} 

1.byteWidth // 8 
UInt32.byteWidth // 4 

È facile capire perché lo sizeof: sia pensato ambiguo ma non sono sicuro che seppellirlo in MemoryLayout fosse la cosa giusta da fare. Vedere il ragionamento dietro lo spostamento di sizeof: a MemoryLayouthere.