如何在 Swift 中使用位操作?
How to work with bit operations in Swift?
我需要形成一个 20 字节的数据包,并通过蓝牙将有效负载发送到硬件外围设备。
这个20字节的数据包内部分为14组数据,每组11位,最后6位为空字符。
因此,总计: 160 位(20 字节)= 14(组)* 11(位)+ 6(空字符)
11位又分为2位、3位、6位各3组。然而,这对主要问题并不重要,我目前可以通过 'Int16' 来形成 11 位。过滤11位我会做移位操作,我知道。
如果我只有一个数据集,那么我应该用空字符填充除前11位之外的所有20个字节,如果是两个数据集,那么除了22位之外的所有字节都应该是空字符。
我面临的问题是形成这个连续的 160 位,因为奇数位是 11。我想采用 'Int' 并进行移位(<<)操作,然后进行按位或( |) 但 Int 是 64 位。
目前我认为采用 20 个固定大小的字符数组适合这种情况。虽然在概念上我认为这是最好的方法,但在编程上我无法形成具有实现这一目标的所有条件的逻辑。我想我需要把所有的逻辑放在一个循环中。
任何人都可以告诉我这是实现此目标的正确方法吗,并指导我解决它,如果这是最好的方法。或者指出任何其他可用的方式。
您不需要在最后将所有数据集打包到 20 字节的数组中,因此将它们保存在长度为 14 的 Int
数组中。使用这种方式更容易。当您需要将其发送到硬件时,将其转换为长度为 20 的 UInt8
数组:
struct DataPacket {
var dataSets = [Int](count: 14, repeatedValue: 0)
func toCArray() -> [UInt8] {
var result = [UInt8](count: 20, repeatedValue: 0)
var index = 0
var bitsRemaining = 8
var offset = 0
for value in self.dataSets {
offset = 10
while offset >= 0 {
let mask = 1 << offset
let bit = ((value & mask) >> offset) << (bitsRemaining - 1)
result[index] |= UInt8(bit)
offset -= 1
bitsRemaining -= 1
if bitsRemaining == 0 {
index += 1
bitsRemaining = 8
}
}
}
return result
}
}
// Usage:
var packet = DataPacket()
packet.dataSets[0] = 0b11111111111
packet.dataSets[1] = 0b00000000011
// etc...
let arr = packet.toCArray()
有很多移位操作正在进行,所以我无法解释所有这些操作。一般的理想是将每个 11 位数据集分配到字节中,并根据需要溢出到下一个字节。
Code Different 提出的解决方案的变体:
struct DataPacket {
var dataSets = [Int16](count: 14, repeatedValue: 0)
func getPacket() -> [UInt8] {
var packet = [UInt8](count: 20, repeatedValue: 0)
var idxPacket = 0
for dataSet in dataSets {
for idxBit in 1...11 {
if dataSet & 1 << (11 - idxBit) != 0 {
packet[idxPacket / 8] |= UInt8(0b1000_0000 >> (idxPacket % 8))
}
idxPacket += 1
}
}
return packet
}
}
我需要形成一个 20 字节的数据包,并通过蓝牙将有效负载发送到硬件外围设备。
这个20字节的数据包内部分为14组数据,每组11位,最后6位为空字符。
因此,总计: 160 位(20 字节)= 14(组)* 11(位)+ 6(空字符)
11位又分为2位、3位、6位各3组。然而,这对主要问题并不重要,我目前可以通过 'Int16' 来形成 11 位。过滤11位我会做移位操作,我知道。
如果我只有一个数据集,那么我应该用空字符填充除前11位之外的所有20个字节,如果是两个数据集,那么除了22位之外的所有字节都应该是空字符。
我面临的问题是形成这个连续的 160 位,因为奇数位是 11。我想采用 'Int' 并进行移位(<<)操作,然后进行按位或( |) 但 Int 是 64 位。
目前我认为采用 20 个固定大小的字符数组适合这种情况。虽然在概念上我认为这是最好的方法,但在编程上我无法形成具有实现这一目标的所有条件的逻辑。我想我需要把所有的逻辑放在一个循环中。
任何人都可以告诉我这是实现此目标的正确方法吗,并指导我解决它,如果这是最好的方法。或者指出任何其他可用的方式。
您不需要在最后将所有数据集打包到 20 字节的数组中,因此将它们保存在长度为 14 的 Int
数组中。使用这种方式更容易。当您需要将其发送到硬件时,将其转换为长度为 20 的 UInt8
数组:
struct DataPacket {
var dataSets = [Int](count: 14, repeatedValue: 0)
func toCArray() -> [UInt8] {
var result = [UInt8](count: 20, repeatedValue: 0)
var index = 0
var bitsRemaining = 8
var offset = 0
for value in self.dataSets {
offset = 10
while offset >= 0 {
let mask = 1 << offset
let bit = ((value & mask) >> offset) << (bitsRemaining - 1)
result[index] |= UInt8(bit)
offset -= 1
bitsRemaining -= 1
if bitsRemaining == 0 {
index += 1
bitsRemaining = 8
}
}
}
return result
}
}
// Usage:
var packet = DataPacket()
packet.dataSets[0] = 0b11111111111
packet.dataSets[1] = 0b00000000011
// etc...
let arr = packet.toCArray()
有很多移位操作正在进行,所以我无法解释所有这些操作。一般的理想是将每个 11 位数据集分配到字节中,并根据需要溢出到下一个字节。
Code Different 提出的解决方案的变体:
struct DataPacket {
var dataSets = [Int16](count: 14, repeatedValue: 0)
func getPacket() -> [UInt8] {
var packet = [UInt8](count: 20, repeatedValue: 0)
var idxPacket = 0
for dataSet in dataSets {
for idxBit in 1...11 {
if dataSet & 1 << (11 - idxBit) != 0 {
packet[idxPacket / 8] |= UInt8(0b1000_0000 >> (idxPacket % 8))
}
idxPacket += 1
}
}
return packet
}
}