Подтвердить что ты не робот

Swift: Как использовать sizeof?

Чтобы интегрироваться с C API при использовании Swift, мне нужно использовать функцию sizeof. В C это было легко. В Swift я попал в лабиринт ошибок типа.

У меня есть этот код:

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

Вторая строка имеет ошибку "NSNumber" не является подтипом "T.Type". Почему это и как его исправить?

4b9b3361

Ответ 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 здесь.