Directly assign UnsafePointer

314 Views Asked by At

Can somebody please explain to me what I'm missing here?

Given

let index: Int32 = 100

Why is this not okay:

// Use of extraneous '&'
let ptr = &index // Type inference?

Or even:

// Use of extraneous '&'
let ptr: UnsafePointer<Int32> = &index

But this is:

{
    func point(num: UnsafePointer<Int32>) -> UnsafePointer<Int32> {
        return num
    }
    let ptr = point(num: &index)
}

This would be the simple equivalent of this in C:

int index = 100;
int *ptr = &index;

Do I really have to define a function that literally takes the referenced value and passes back the very same reference? Something feels wrong about it. It seems like I'm missing something here, maybe even fundamental.

How do I assign an UnsafePointer to the memory address of the type it is (Int32 in this case)???

Thanks!

Edit:

Ultimately what I'm attempting to accomplish is, I need to write several various structures into a binary file. The variable index would be a property of a structure. The path I'm going down now involves a file OutputStream. I don't mind receiving suggestions on this, but gets out of scope of the original question.

1

There are 1 best solutions below

4
On BEST ANSWER

I don't know the precise rationale, but presumably let ptr = &index isn't allowed because there's no guarantee that you can dereference ptr without invoking undefined behaviour (assuming index isn't a global or static stored variable – the only cases where Swift guarantees stable and unique pointer values).

Unlike other languages, Swift doesn't guarantee that a local variable will remain initialised until the end of the scope it's declared in – the optimiser is free to deinitialise it earlier. Allowing let ptr = &index would therefore make it far too easy to write unsound code.

It's worth noting that your example of:

func point(num: UnsafePointer<Int32>) -> UnsafePointer<Int32> {
    return num
}
let ptr = point(num: &index)

is also unsound. Attempting to dereference ptr from let ptr = point(num: &index) is undefined behaviour, as the inout-to-pointer argument conversion produces a temporary pointer only valid for the duration of the function call.

If you want a scoped temporary pointer to a value, you can use withUnsafePointer(to:) – for example:

func baz() {
  var foo = 5
  withUnsafePointer(to: &foo) { ptr in
    // use `ptr` here – do not escape it!
  }

  // In Swift 4.2 you can also use `withUnsafePointer(to:)` on let constants.
  let bar = 5
  withUnsafePointer(to: bar) { ptr in
    // use `ptr` here – do not escape it!
  }
}

Note that the pointer is only valid for the duration of the closure – attempting to escape it will lead to undefined behaviour.