Swift: Как использовать sizeof?
Чтобы интегрироваться с C API при использовании Swift, мне нужно использовать функцию sizeof. В C это было легко. В Swift я попал в лабиринт ошибок типа.
У меня есть этот код:
var anInt: Int = 5
var anIntSize: Int = sizeof(anInt)
Вторая строка имеет ошибку "NSNumber" не является подтипом "T.Type". Почему это и как его исправить?
Ответы
Ответ 1
Используйте sizeof следующим образом:
let size = sizeof(Int)
sizeof
использует этот тип в качестве параметра.
Если вы хотите размер переменной anInt
, вы можете передать поле dynamicType
в sizeof
.
Так же:
var anInt: Int = 5
var anIntSize: Int = sizeof(anInt.dynamicType)
Или проще (указана пользователем102008):
var anInt: Int = 5
var anIntSize: Int = sizeofValue(anInt)
Ответ 2
Обновлено для Swift 3
Будьте осторожны, что MemoryLayout<T>.size
означает что-то другое, чем sizeof
в C/Obj-C. Вы можете прочитать этот старый поток https://devforums.apple.com/message/1086617#1086617
Swift использует общий тип, чтобы сделать его явным, что число известно во время компиляции.
Подводя итог, MemoryLayout<Type>.size
- это пространство, необходимое для одного экземпляра, а MemoryLayout<Type>.stride
- расстояние между последовательными элементами в смежном массиве. MemoryLayout<Type>.stride
в Swift совпадает с sizeof(type)
в C/Obj-C.
Чтобы дать более конкретный пример:
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
Ответ 3
Swift 3 теперь имеет MemoryLayout.size(ofValue:)
который может динамически искать размер.
Использование универсальной функции, которая, в свою очередь, использует MemoryLayout<Type>
приведет к неожиданным результатам, если вы, например, передадите ей ссылку на тип протокола. Это происходит потому, что, насколько я знаю, компилятор имеет всю информацию о типе, необходимую для заполнения значений во время компиляции, что неочевидно при просмотре вызова функции. Затем вы получите размер протокола, а не текущее значение.
Ответ 4
В Xcode 8 с Swift 3 beta 6 нет функции sizeof(). Но если вы хотите, вы можете определить его для своих нужд. Эта новая функция sizeof работает так, как ожидалось, с массивом. Это невозможно с помощью старой встроенной функции sizeof.
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
Вам нужны все версии функции sizeof, чтобы получить размер переменной и получить правильный размер типа данных и массива.
Если вы определяете только вторую функцию, то sizeof (UInt8.self) и sizeof (Bool.self) приведет к "8". Если вы определяете только первые две функции, то sizeof (testArray) приведет к "8".
Ответ 5
Swift 4
Начиная с Xcode 9, теперь есть свойство с именем .bitWidth
, которое предоставляет другой способ записи sizeof:
функции для экземпляров и целочисленных типов:
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
Но для согласованности было бы больше смысла заменить sizeof:
на .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
Легко понять, почему sizeof:
считается неоднозначным, но я не уверен, что похоронить его в MemoryLayout было правильным решением. Посмотрите MemoryLayout
смещения sizeof:
на MemoryLayout
здесь.