How do I create an UnsafePointer<X> variable (not parameter)?

92 views
Skip to first unread message

Jens Alfke

unread,
Nov 5, 2015, 5:04:16 PM11/5/15
to Swift Language
Given a variable of type X, how do I create an UnsafePointer<X> variable that points to it? This doesn’t work:

typealias X = UInt32
var x: X = 1234
var p: UnsafePointer<X> = &x

The compiler complains “‘&’ used with non-inout argument” and helpfully offers to remove the “&”, which of course just makes things worse.

The closest I’ve come is:

var p = UnsafePointer<X>(&x)

which fails with “ambiguous use of ‘init’”. The problem is that UnsafePointer has an init that takes UnsafePointer and another that takes UnsafeMutablePointer, and “&x” could be converted to either of those.
But if I try to disambiguate like this:

var p = UnsafePointer<X>(&x as UnsafePointer<X>)

then the compiler again complains  “‘&’ used with non-inout argument” :-p

Why am I doing this? Because I’m calling a C function that takes a parameter of type "const X*”, and I need to either pass the address of an X variable, or nil, depending on some condition. That means I need to pre-create an UnsafePointer<X> that will either point to the variable or be nil, and pass that to the function.

—Jens

PS: I’m using Xcode 7.1 on El Capitan.

Ken Ferry

unread,
Nov 5, 2015, 5:13:18 PM11/5/15
to Jens Alfke, Swift Language
For this purpose you should be able to pass &x directly to the function. 



Constant Pointers

When a function is declared as taking a UnsafePointer<Type> argument, it can accept any of the following:

  • nil, which is passed as a null pointer.
  • An UnsafePointer<Type>UnsafeMutablePointer<Type>, or AutoreleasingUnsafeMutablePointer<Type> value, which is converted to UnsafePointer<Type> if necessary.
  • String value, if Type is Int8 or UInt8. The string will automatically be converted to UTF8 in a buffer that lasts for the duration of the call.
  • An inout expression whose left-hand side operand is of type Type, which is passed as the address of the left-hand side identifier.
  • [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call.

If you have declared a function like this one:

  1. func takesAPointer(x: UnsafePointer<Float>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: Float = 0.0
  2. var p: UnsafePointer<Float> = nil
  3. takesAPointer(nil)
  4. takesAPointer(p)
  5. takesAPointer(&x)
  6. takesAPointer([1.0, 2.0, 3.0])


Somewhat more generally,

/// Invokes `body` with an `UnsafePointer` to `arg` and returns the
/// result. Useful for calling Objective-C APIs that take "in/out"
/// parameters (and default-constructible "out" parameters) by pointer.
public func withUnsafePointer<T, Result>(inout arg: T, @noescape _ body: UnsafePointer<T> throws -> Result) rethrows -> Result

and for non-structs:

/// Returns an `UnsafePointer` to the storage used for `object`.  There's
/// not much you can do with this other than use it to identify the
/// object.
@warn_unused_result
public func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>

-ken

Jens Alfke

unread,
Nov 5, 2015, 5:24:28 PM11/5/15
to Swift Language
I did figure out a way to do it, but it’s a silly kludge:

func unsafify(x: UnsafePointer<X>) -> UnsafePointer<X> {
    return x
}

var p: UnsafePointer<X> = nil
if (x > 100) { // some silly condition
    p = unsafify(&x)
}

This seems to point [sic] to a hole in the language — the conversion from X to UnsafePointer<X> is only available as part of parameter-passing, so here I have to artificially go through a no-op function call to invoke it.

—Jens

Jens Alfke

unread,
Nov 5, 2015, 5:25:49 PM11/5/15
to Ken Ferry, Swift Language

On Nov 5, 2015, at 2:13 PM, Ken Ferry <kenf...@gmail.com> wrote:

For this purpose you should be able to pass &x directly to the function. 

Yup, and that’s what I’ve been doing in other places in my code. However in this place I need to pass either &x or nil, depending on circumstances. And that led to a lot of pain.

—Jens

Adam Sharp

unread,
Nov 5, 2015, 5:28:30 PM11/5/15
to swift-l...@googlegroups.com
I think the withUnsafePointer() family of functions is probably more what you're after. The pointer is then lexically scoped to the closure that you pass. If you need to allocate memory on the heap, you can use UnsafePointer<T>.alloc() and copy the memory from the pointer you get via withUnsafePointer().

Kevin Ballard

unread,
Nov 5, 2015, 5:34:23 PM11/5/15
to swift-l...@googlegroups.com
That's not just a kludge; it's actually fundamentally unsafe. Swift's inout parameters follow a writeback semantic model; for every call to a function with an inout parameter, it behaves as though it makes a local copy of the value, passes a pointer to that to the function, and then when the function returns it writes the local copy back to the original location. Swift does have an optimization where if you pass a reference to a memory location (e.g. variable or stored property), it will actually just pass the pointer to that location in to the function instead of doing a literal writeback, but you're not supposed to rely on this optimization. As long as you don't rely on this optimization, you can convert a stored property to a computed property without breaking any code.
 
Because of that, constructing an UnsafePointer<X> like you're doing is fundamentally unsafe; you're holding onto a pointer value past the scope where the pointer is valid.
 
There exists functions called withUnsafePointer() and withUnsafeMutablePointer() (and variants of these) that give you a pointer to a value that's valid for a nested scope. That's the supported way of working with pointers, but holding onto the pointer after the scope is over is a violation of the language semantics.
 
As a side note, these same semantics are why the OSAtomic family of functions are technically unsafe to call from Swift (because the atomic operations they perform might actually be occurring on local copies and not on the original memory location) and everyone who does so is relying on the aforementioned optimization.
 
-Kevin Ballard
--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swift-languag...@googlegroups.com.
To post to this group, send email to swift-l...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
 

Kevin Ballard

unread,
Nov 5, 2015, 5:36:14 PM11/5/15
to swift-l...@googlegroups.com
If you're allocating on the heap with UnsafePointer<T>.alloc() then withUnsafePointer() is entirely superfluous, because calling `withUnsafePointer(&ptr.memory)` is just going to end up creating the exact same value that `ptr` already represents (after optimization; technically according to the semantics of the language it may give you a pointer to a temporary copy of `ptr.memory`, but in practice it will just give you `ptr`).
 
-Kevin
--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swift-languag...@googlegroups.com.
To post to this group, send email to swift-l...@googlegroups.com.

Jens Alfke

unread,
Nov 5, 2015, 6:06:06 PM11/5/15
to Kevin Ballard, swift-l...@googlegroups.com
On Nov 5, 2015, at 2:34 PM, Kevin Ballard <ke...@sb.org> wrote:

Because of that, constructing an UnsafePointer<X> like you're doing is fundamentally unsafe; you're holding onto a pointer value past the scope where the pointer is valid.

You’re right; I’d forgotten about that bit. 

There exists functions called withUnsafePointer() and withUnsafeMutablePointer() (and variants of these) that give you a pointer to a value that's valid for a nested scope. That's the supported way of working with pointers

Supported, but not well-documented o_O
The “Swift And Objective-C” book only describes how to pass a value to an UnsafePointer parameter, not how to do anything else with pointers.
I did dig through the API docs, but assumed I’d find the answer in the UnsafePointer API … I didn’t think of looking through all the global functions. Thanks for revealing the answer!

—Jens
Reply all
Reply to author
Forward
0 new messages