【问题标题】:How do I set integer endianness using htonl in Swift?如何在 Swift 中使用 htonl 设置整数字节顺序?
【发布时间】:2014-06-24 19:21:46
【问题描述】:

我正在尝试在 Swift 中使用 htonl() 设置整数字节顺序,但编译器没有找到 htonl() 方法。

我一直以此为参考:Append NSInteger to NSMutableData

这是我的代码:

import Foundation
import CFNetwork
import CoreFoundation

var data = NSMutableData()
var number : UInt32 = 12
var convertedNumber : UInt32 = htonl(number)
data.appendBytes(&convertedNumber, length: 4)

我刚刚在操场上运行它。错误是:

Use of unresolved identifier 'htonl'

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    从 Xcode 6 Beta 3 开始,所有整数类型都有一个 bigEndian 方法 返回整数的大端表示并更改 必要时字节顺序。示例:

    var data = NSMutableData()
    var number : UInt32 = 0x12345678
    var convertedNumber = number.bigEndian
    data.appendBytes(&convertedNumber, length: 4)
    print(data)
    // Output: <12345678>
    

    Swift 3 更新:

    let data = NSMutableData()
    let number: UInt32 = 0x12345678
    var convertedNumber = number.bigEndian
    data.append(&convertedNumber, length: 4)
    

    或者,使用新的Data 值类型:

    var data = Data()
    let number: UInt32 = 0x12345678
    var convertedNumber = number.bigEndian
    withUnsafePointer(to: &convertedNumber) {
        data.append(UnsafeRawPointer($0).assumingMemoryBound(to: UInt8.self), count: 4)
    }
    

    【讨论】:

    • 如果您正在寻找相反的方向(网络到主机),您可以使用UInt32(bigEndian: number),以及类似的inits 用于其他整数类型。
    【解决方案2】:

    更新:Martin R 的答案是当前 Swift 版本的正确答案:https://stackoverflow.com/a/24653879/195691

    --

    您应该使用CFSwapInt32HostToBig() CoreFoundation 方法,因为htonl 很可能实现为不能在swift 中运行的C 宏。

    但是,目前看来这在 Swift 游乐场中不起作用。尽管 CoreFoundation 文档现在在 Swift 中包含用于字节交换方法的方法签名,但我收到了错误 Playground execution failed: error: error: Couldn't lookup symbols: __OSSwapInt32

    有趣的是,&lt;arpa/inet.h&gt; 的至少一部分似乎已移植到 swift,因为 inet_ntoa()inet_addr() 等方法可用于 Swift,但 htonl 系列不可用。

    【讨论】:

    • 太棒了,谢谢!看起来这会奏效。我最终在桥接头/native-c 中实现了 htonl(),但我会切换到这个。
    • 对。 htonl/htons 等是一个宏,因此不会导入到 Swift 中(像 ioctl/fcntl 这样的可变参数 C 函数是另一个常见的缺失)。如果你知道字节序很容易重新实现:func ntohs(value: CUnsignedShort) -> CUnsignedShort { // hm, htons 在 OSX 中不是 func 并且宏没有映射 return (value > 8); } let htons = ntohs // 同样的事情,交换字节 :-)
    • 其实 CFSwapInt32HostToBig 和朋友们现在可以在 Xcode 6.1.1 自带的 Swift 中使用 :)
    • @MartinR 这可能是真的,但UInt32.bigEndianUInt32.littleEndianUInt32.byteSwapped 似乎比使用CFSwapInt32HostToBig 更好
    • PSA 5.bigEndian.littleEndian 不等于 5!然而,CFSwapInt16BigToHost(CFSwapInt16HostToBig(5)) 实际上等于 5!
    【解决方案3】:

    不要像 Alex Pretzlav 建议的那样使用 CFSwapInt32HostToBig(),而是应该使用

    CFSwapInt32()
    

    而不是

    ntonl() and ntohl()
    

    CFSwapInt16()
    

    而不是

    ntons() and ntohs()
    

    你的代码应该是这样的

    import Foundation
    import CFNetwork
    import CoreFoundation
    
    var data = NSMutableData()
    var number : UInt32 = 12
    var convertedNumber : UInt32 = CFSwapInt32(number)
    data.appendBytes(&convertedNumber, length: 4)
    

    还有

    CFSwapInt64()
    

    用于 8 字节整数交换。

    编辑 1

    当然,您应该只在具有小端整数的处理器上使用这些函数,因为我提供的函数无论如何都会执行字节交换。

    【讨论】:

    • 我不明白你的回答。你说不要使用CFSwapInt32HostToBig,建议你改用CFSwapInt32,然后是“你应该只在具有小端整数的处理器上使用这些函数”……CFSwapInt32HostToBig 的全部意义在于它可以交换,或者不会,具体取决于平台。
    猜你喜欢
    • 1970-01-01
    • 2014-02-14
    • 2010-11-26
    • 2019-01-12
    • 2012-03-28
    • 2010-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多