What is the correct way to reinterpret an entity in Swift?

谁都会走 提交于 2019-12-12 22:22:54

问题


There are cases when you have to deal with a structure of certain type, but the upstream API requires you to present it though a pointer to another type at other places.

For instance, Unix Bind is expecting its second argument to be a pointer to a sockaddr, whereas the constructor should be sockaddr_in.

For now I'm sticking to a two-layer with*:

var sa = sockaddr_in(/* ... */)

withUnsafePointer(to: &sa) { _sa in
  _sa.withMemoryRebound(to: sockaddr.self, capacity: 1) { __sa in
    let err = bind(fd, __sa, socklen_t(saSize))
    precondition(err == 0)
  }
}

However, I'm discouraged by noisiness of this approach. When I use unsafeBitCast between pointer types:

bind(fd, unsafeBitCast(__sa, to: UnsafeMutablePointer<sockaddr>.self), socklen_t(saSize))

Then the compiler warns me not to do so, and recommends resort to withMemoryRebound.

When I use an in-place constructed pointer:

UnsafeMutablePointer(mutating: &sa).withMemoryRebound(to: sockaddr.self, capacity: 1) { _sa in
  let err = bind(fd, _sa, socklen_t(saSize))
  precondition(err == 0)
}

Then it works as well as the initial version, and rids us of one level of nesting. Although it looks more frail than with*. Also it's unclear, if the in-place pointer is the correct approach, why withUnsafePointer even exists.

Having that said, what is the canonical way to reinterpret a structure in Swift?


回答1:


Your first method is the correct one, using withUnsafePointer() and withMemoryRebound(), as one can see from the various examples provided in UnsafeRawPointer Migration, e.g.

In Swift 3, the user should explicitly rebind memory to a different type:

let result = withUnsafePointer(to: &addr) {
  // Temporarily bind the memory at &addr to a single instance of type sockaddr.
  $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
    connect(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
  }
}

The other approach

UnsafeMutablePointer(mutating: &sa).withMemoryRebound(...) { ... }

looks fragile to me. sa is passed as an inout parameter to the constructor of UnsafeMutablePointer(), but that may be the address of temporary storage, and there is no guarantee that it is still valid when the constructor has returned and the closure is called.



来源:https://stackoverflow.com/questions/45561367/what-is-the-correct-way-to-reinterpret-an-entity-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!