在Swift中强制转换到不同的C结构不安全指针
我想从Swift调用Posix套接字函数在Swift中强制转换到不同的C结构不安全指针,swift,swift3,unsafe-pointers,Swift,Swift3,Unsafe Pointers,我想从Swift调用Posix套接字函数socket和bindsocket非常简单,需要Int32s,但是bind会导致问题,因为我在指针中有一个sockaddr\u,但它需要一个sockaddr指针。在C中,这将是一个演员阵容,如: bind(sock, (struct sockaddr *)&sockAddress, sizeof(sockAddress)) 以下是Swift的一个尝试: let sock = socket(PF_INET, SOCK_STREAM, IPPROTO
socket
和bind
socket
非常简单,需要Int32
s,但是bind
会导致问题,因为我在指针中有一个sockaddr\u,但它需要一个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))
let sock=socket(PF_INET、sock_STREAM、IPPROTO_TCP)
var sockAddress=sockaddr_in()
绑定(sock和sockAddress,UInt32(MemoryLayout.size))
bind
行编译失败,原因是:无法将类型为“sockaddr\u in”的值转换为预期的参数类型“sockaddr”
我如何投射指针 你可以这样写:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
sockaddrInPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) {sockaddrPtr in
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
}
使用unsafepointer(指向:&sockAddress){sockaddrInPtr-in
sockaddrInPtr.withMemoryRebound(收件人:sockaddr.self,容量:1){sockaddrPtr in
绑定(sock、sockaddrPtr、UInt32(MemoryLayout.stride))
}
}
或者有人建议这样可能更好:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
let sockaddrPtr = UnsafeRawPointer(sockaddrInPtr).assumingMemoryBound(to: sockaddr.self)
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
使用unsafepointer(指向:&sockAddress){sockaddrInPtr-in
让sockaddrPtr=UnsafeRawPointer(sockaddrInPtr).assumingmemorybind(to:sockaddr.self)
绑定(sock、sockaddrPtr、UInt32(MemoryLayout.stride))
}
也许会有帮助
(更新)
如中所述,现在MemoryLayout.stride
和MemoryLayout.size
返回与C的sizeof
一致的值,其中T是导入的C结构。我将在这里保留我的步幅
版本的答案,但在本例中,这不是“必需的”。在Swift 3中,您必须“重新绑定”指针
(比较):
let sock=socket(PF_INET、sock_STREAM、IPPROTO_TCP)
var sockAddress=sockaddr_in()
let result=withUnsafePointer(指向:&sockAddress){
$0.withMemoryRebound(收件人:sockaddr.self,容量:1){
绑定(sock,$0,socklen_t(MemoryLayout.stride))
}
}
备注:
- 不需要
let sock:Int32
和var sockAddress:sockaddr\u中的类型注释
memset()
不是必需的,因为sockaddr\u in()
初始化
将所有结构成员设置为零
- C
sizeof
的Swift等价物是stride
(包括
可能的结构填充),而不是大小
(不包括
结构填充)。(这个“问题”已经不存在了。
对于从C导入的结构,stride
和size
具有相同的值。)
Swift 5用unsafebytes(UnsafePointer)废弃了,
,因此下面是我对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)
}
哎呀,我没看到你的答案:)表明UnsafeRawPointer
在某些情况下有效。但我不确定在这种情况下哪个更好。欢迎提供更多信息。根据,这两个都是正确的,据我所知,还有一点是“withMemoryRebound”。@MartinR,谢谢。我看了一眼这篇文章,就不能肯定了。我会花更多的时间再读一遍。这里有一个例子,“大小”不起作用,只有“步幅”。它是低级的…如果您尝试使用sizeof
,Xcode建议将其替换为size
@RobN:然后为Xcode:)提交错误报告。在C中,sizeof是结构的大小,包括结尾可能的填充。在Swift中,步幅包括结构填充,而大小不包括。Ha.)好吧,我会让别人做的,因为我不知道这是错的。我确实根据你的其他评论修正了这个问题,删除了噪音代码。谢谢@RobN:如果结构的末尾没有填充,这没有什么区别。大步走,你就安全了。这里有一个(可能是异国情调的)情况,使用大小不起作用。
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)
}