如何在 Swift 中使用 htonl 设置整数字节顺序?

Posted

技术标签:

【中文标题】如何在 Swift 中使用 htonl 设置整数字节顺序?【英文标题】:How do I set integer endianness using htonl in Swift? 【发布时间】: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'

【问题讨论】:

【参考方案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://***.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 的全部意义在于它可以交换,或者不会,具体取决于平台。

以上是关于如何在 Swift 中使用 htonl 设置整数字节顺序?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JSONDecoder Swift 解码具有整数值的字符串键 [关闭]

使用 Swift,从 plist 加载数据时,如何区分布尔值和整数值?

如何限制 UITextField 在 Swift 中只接受数字?

在 Swift 3 中使用 NSNumber 和整数值

如何使用Swift在Xcode上创建自定义数字键盘? [关闭]

如何通过在 swift playground 中传递 Int 数组来创建求和函数并调用它?