Swift: How to use sizeof?

Swift

Swift Problem Overview


In order to integrate with C API's while using Swift, I need to use the sizeof function. In C, this was easy. In Swift, I am in a labyrinth of type errors.

I have this code:

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

The second line has the error "'NSNumber' is not a subtype of 'T.Type'". Why is this and how do I fix it?

Swift Solutions


Solution 1 - Swift

Updated for Swift 3

Be careful that MemoryLayout<T>.size means something different than sizeof in C/Obj-C. You can read this old thread https://devforums.apple.com/message/1086617#1086617

Swift uses an generic type to make it explicit that the number is known at compile time.

To summarize, MemoryLayout<Type>.size is the space required for a single instance while MemoryLayout<Type>.stride is the distance between successive elements in a contiguous array. MemoryLayout<Type>.stride in Swift is the same as sizeof(type) in C/Obj-C.

To give a more concrete example:

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

Solution 2 - Swift

Use sizeof as follows:

let size = sizeof(Int)

sizeof uses the type as the parameter.

If you want the size of the anInt variable you can pass the dynamicType field to sizeof.

Like so:

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

Or more simply (pointed out by user102008):

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

Solution 3 - Swift

Swift 3 now has MemoryLayout.size(ofValue:) which can look up the size dynamically.

Using a generic function that in turn uses MemoryLayout<Type> will have unexpected results if you e.g. pass it a reference of protocol type. This is because — as far as I know — the compiler then has all the type information it needs to fill in the values at compile time, which is not apparent when looking at the function call. You would then get the size of the protocol, not the current value.

Solution 4 - Swift

In Xcode 8 with Swift 3 beta 6 there is no function sizeof (). But if you want, you can define one for your needs. This new sizeof function works as expected with an array. This was not possible with the old builtin sizeof function.

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

You need all versions of the sizeof function, to get the size of a variable and to get the correct size of a data-type and of an array.

If you only define the second function, then sizeof(UInt8.self) and sizeof(Bool.self) will result in "8". If you only define the first two functions, then sizeof(testArray) will result in "8".

Solution 5 - Swift

Swift 4

From Xcode 9 onwards there is now a property called .bitWidth, this provides another way of writing sizeof: functions for instances and integer types:

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

But it would make more sense for consistency to replace sizeof: with .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

It is easy to see why sizeof: is thought ambiguous but I'm not sure that burying it in MemoryLayout was the right thing to do. See the reasoning behind the shifting of sizeof: to MemoryLayout here.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1021430View Question on Stackoverflow
Solution 1 - SwiftRay FixView Answer on Stackoverflow
Solution 2 - SwiftwbennettView Answer on Stackoverflow
Solution 3 - SwiftAndreasView Answer on Stackoverflow
Solution 4 - Swiftj.s.comView Answer on Stackoverflow
Solution 5 - SwiftsketchyTechView Answer on Stackoverflow