Swift: How to Use Sizeof

Swift: How to use sizeof?

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)

Swift use sizeof with Int32 Array

You can get the number of elements in an array simply with

let count = testArray.count

and the total number of bytes of its elements with

var arrayLength = testArray.count * sizeof(Int32)
// Swift 3:
var arrayLength = testArray.count * MemoryLayout<Int32>.size

sizeof is used with types and sizeofValue with values, so both

var arrayLength = sizeof([Int32])
var arrayLength = sizeofValue(testArray)

would compile. But that gives you the size of the struct Array, not the size
of the element storage.

Use of unresolved identifier 'sizeof'

I would rewrite your code in Swift 4 as:

var positionToSend = car.position
let dataSend = Data(bytes: &positionToSend, count: MemoryLayout.size(ofValue: positionToSend))
do {
try match.sendData(toAllPlayers: dataSend, with: .unreliable)
} catch {
//Write code for `if error != nil`...
print(error)
}

You do not need withUnsafePointer.

In Swift, how to get the true size of an `Any` variable?

I'll begin with some technical details about the limitations of Any in this case.

So, what is Any? It's an empty protocol to which every type implicitly conforms to.

And how does the compiler represent variables of protocol types? It's by wrapping the actual value in an existential container. So basically when you're referencing a variable of this kind, you're actually talking to the container (well, actually not you, but the compiler is :).

An existential container has a layout that can be represented like this C structure:

struct OpaqueExistentialContainer {
void *fixedSizeBuffer[3];
Metadata *type;
WitnessTable *witnessTables[NUM_WITNESS_TABLES];
};

The container elements are greatly explained in this document, I'll also try to summarize them here:

  • fixedSizeBuffer either holds the whole value, if it takes less than 24 bytes, or holds a pointer to a heap allocated zone, containing the value
  • type is a pointer to the type metadata
  • witnessTables is what makes this layout occupy various sizes, as the number of protocol witness tables can vary from zero to virtually any number of protocols.

So, with the above in mind:

  • Any needs no witness tables, thus it occupies 32 bytes
  • a single protocol variable occupies 40 byes
  • a composed protocol variable occupies 32 + N*8, where N is the number of "independent" protocols involved in the composition

Note that the above is true if there are no class protocols involved, if a class protocol is involved, then the existential container layout is a little bit simplified, this is also better described in the linked document from above.


Now, back to the problem from the question, it's the existential container created by the compiler the one which prevents you from accessing the actual type. The compiler doesn't make this structure available, and transparently translates any calls to protocol requirements to dispatches through the witness tables stored in the container.

But, might I ask you, why are you circulating Any? I assume you don't want to handle all possible and future types in a generic manner. A marker protocol might help here:

protocol MemoryLayouted { }

extension MemoryLayouted {
var memoryLayoutSize: Int { MemoryLayout.size(ofValue: self) }
}

Then all you have left to do is to add conformance for the types you want to support:

extension Int: MemoryLayouted { }
extension String: MemoryLayouted { }
extension MyAwesomeType: MemoryLayouted { }

With the above in mind, you can rewrite your initial code to something like this:

let regularInt: Int = 1
let anyInt: MemoryLayouted = 2

print(regularInt.memoryLayoutSize) // 8
print(anyInt.memoryLayoutSize) // 8

You get consistent behaviour and type safety, a type safety that might translate to a more stable application.


P.S. A hacky approach, that allows you to use Any, might pe possible by unpacking the existential container via direct memory access. The Swift ABI is stable at this point, so the existential container layout is guaranteed not to change in the future, however not recommending going that route unless absolutely necessary.

Maybe someone that stumbles this question and has experience in the ABI layout code can provide the code for it.

Get the size (in bytes) of an object on the heap

One option on Apple platforms, because Swift classes are currently built on top of Objective-C classes there, would be to use the Obj-C runtime function class_getInstanceSize, which gives you the size in bytes of an instance of the class, including any padding.

// on a 64-bit machine (1 word == 8 bytes)...

import Foundation

class C {}
print(class_getInstanceSize(C.self)) // 16 bytes metadata for empty class
// (isa ptr + ref count)

class C1 {
var i = 0
var i1 = 0
var b = false
}

print(class_getInstanceSize(C1.self)) // 40 bytes
// (16 metadata + 24 ivars, 8 for i + 8 for i1 + 1 for b + 7 padding)

sizeof() gives an error for array argument

You can iterate through the array like this:

    let graphPoint = // ...
var radius = CGFloat(0.0)

for a in graphPoint {
let b = sqrt(pow(a.x - point.x, 2.0) + pow(a.y - point.y, 2.0))
if b > radius {
radius = b
}
}

I often have this error "operator X cannot be applied to two Y operands", and usually the problem comes from somewhere else, in this particular case it's because Swift sizeof uses the type and not the var as Glenn said.

Size of struct with optionals in swift

Int? aka Optional<Int> is an enum type and requires 9 bytes: 8 bytes for the integer (if we are on a 64-bit platform) plus one byte for the case discriminator.

In addition, each integer is aligned in memory to its natural (8 byte) boundary, by inserting padding bytes.

So your struct would look like this in memory:

i1 i1 i1 i1 i1 i1 i1 i1      // 8 bytes for the first integer
c1 p1 p1 p1 p1 p1 p1 p1 // 1 byte for the first case discriminator,
// ... and 7 padding bytes
i2 i2 i2 i2 i2 i2 i2 i2 // 8 bytes for the second integer
c2 p2 p2 p2 p2 p2 p2 p2 // 1 byte for the second case discriminator
// ... and 7 padding bytes
i3 i3 i3 i3 i3 i3 i3 i3 // 8 bytes for the third integer
c3 // 1 byte for the third case discriminator

That makes a total of 41 bytes.

If SampleStruct values are stored contiguously in an array then additional padding is inserted between the elements to ensure that each value starts on a 8-byte boundary. This additional padding is taken into account by the stride:

print(MemoryLayout<SampleStruct>.size)    // 41
print(MemoryLayout<SampleStruct>.stride) // 48

You can find the gory details in the Type Layout document of the Swift documentation.



Related Topics



Leave a reply



Submit