在Swift中强制转换到不同的C结构不安全指针

在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

我想从Swift调用Posix套接字函数
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)
    }