我想从Swift调用Posix套接字函数socket
和bind
。 socket
非常简单 - 需要Int32
,但bind
会导致问题,因为我有一个sockaddr_in
指针,但它需要一个sockaddr
指针。在C中,这将是一个演员,如:
bind(sock, (struct sockaddr *)&sockAddress, sizeof(sockAddress))
这是Swift的尝试:
let sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
var sockAddress = sockaddr_in()
bind(sock, &sockAddress, UInt32(MemoryLayout<sockaddr_in>.size))
bind
行无法编译:无法转换类型&#39; sockaddr_in&#39;的值预期参数类型&#39; sockaddr&#39;
如何投射指针?
答案 0 :(得分:7)
你可以这样写:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
sockaddrInPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) {sockaddrPtr in
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
}
或有人建议这可能会更好:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
let sockaddrPtr = UnsafeRawPointer(sockaddrInPtr).assumingMemoryBound(to: sockaddr.self)
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
This article可能会有所帮助。
(UPDATE)
如the link shown by Martin R中所述,现在MemoryLayout<T>.stride
和MemoryLayout<T>.size
返回的值与C sizeof
一致,其中T是导入的C结构。我会在这里保留stride
版本的答案,但这不是&#34;必需&#34;在这种情况下现在。
答案 1 :(得分:4)
在Swift 3中你必须&#34;重新绑定&#34;指针 (比较SE-0107 UnsafeRawPointer API):
let sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
var sockAddress = sockaddr_in()
let result = withUnsafePointer(to: &sockAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
}
}
说明:
不需要let sock: Int32
和var sockAddress: sockaddr_in
中的类型注释。
memset()
不是必需的,因为sockaddr_in()
初始化
所有结构成员都归零。
C (这&#34;问题&#34;不再存在。
对于从C导入的结构,sizeof
的Swift等价物为stride
(包括
一个可能的结构填充),而不是size
(不包括
struct padding)。stride
和size
具有相同的值。)
答案 2 :(得分:0)
Swift 5淘汰了withUnsafeBytes(UnsafePointer<sockaddr>)
,所以下面是我对Swift 5所做的事情:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
return withUnsafeBytes { (p: UnsafeRawBufferPointer) -> String? in
let addr = p.baseAddress?.assumingMemoryBound(to: sockaddr.self)
guard getnameinfo(addr, socklen_t(self.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
return nil
}
return String(cString: hostname)
}