3

我想从 Swift调用socketPosix套接字函数。很简单——它需要s,但会导致问题,因为我有一个指针,但它需要一个指针。在 C 中,这将是一个演员表,例如:bindsocketInt32bindsockaddr_insockaddr

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行无法编译:无法将“sockaddr_in”类型的值转换为预期的参数类型“sockaddr”

如何投射指针?

4

3 回答 3

8

你可以这样写:

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))
}

这篇文章可能会有所帮助。


(更新)如Martin R 所示链接中所述,现在MemoryLayout<T>.strideMemoryLayout<T>.size返回与 C's 一致的相同值sizeof,其中 T 是导入的 C 结构。我会stride在这里保留我的答案版本,但现在在这种情况下这不是“必需的”。

于 2016-08-27T18:57:22.397 回答
4

在 Swift 3 中,您必须“重新绑定”指针(比较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 的 Swift 等效项sizeofstride(包括可能的结构填充),而不是size(不包括结构填充)。(这个“问题”不再存在。对于从 C 导入的结构,stride并且size具有相同的值。)

于 2016-08-27T18:57:48.070 回答
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)
    }
于 2019-07-10T10:16:39.070 回答