可能会溢出。
为了说明一个概念以后用于诸如UInt128
和UInt256
之类的较大数据类型,我正在尝试执行以下功能:
我的功能采用2 UInt8
s,将第一个(理论上的位置更重要)移至左8,然后添加 int2
(理论上是较低的位)
func combineBits(int1: UInt8, int2: UInt8) -> UInt16 {
let x: UInt16 = (int1 << 8) + int2
return x
}
我需要做一些事情来避免错误:(int1 << 8) + int2
不等于指定的类型UInt16
?
您必须显式将较小的类型转换为较大类型:
func combineBits(int1: UInt8, int2: UInt8) -> UInt16 {
let x: UInt16 = (UInt16(int1) << 8) + UInt16(int2)
return x
}
这也使显式类型注释不必要:
func combineBits(int1: UInt8, int2: UInt8) -> UInt16 {
let x = (UInt16(int1) << 8) + UInt16(int2)
return x
}
可以缩短为:
func combineBits(int1: UInt8, int2: UInt8) -> UInt16 {
return UInt16(int1) << 8 + UInt16(int2)
}
必须在移动/添加之前完成较大类型的转换,
只是为了娱乐,替代方案是使用 Data
func combineBits(int1: UInt8, int2: UInt8) -> UInt16 {
return Data([int2, int1]).withUnsafeBytes{ $0.pointee }
}
这是我要做的,以一种endian-correct的方式:
extension UInt16 {
init(high: UInt8, low: UInt8) {
self.init(littleEndian: UInt16(high) << 8 | UInt16(low))
}
}
let i = UInt16(high: 0xAB, low: 0xCD)
// Represented on Little Endian platforms as 0xABCD
// Represented on Big Endian platforms as 0xCDAB
这是一个更涉及的通用解决方案:
protocol PairedUnsignedInteger: UnsignedInteger {
associatedtype SignedSelf: PairedSignedInteger
}
protocol PairedSignedInteger: SignedInteger {
associatedtype UnsignedSelf: PairedUnsignedInteger
}
protocol BitPattternInitializable: FixedWidthInteger {
associatedtype BitPatternSource: FixedWidthInteger
init(bitPattern: BitPatternSource)
}
protocol UnsignedBitPattternInitializable: BitPattternInitializable, PairedSignedInteger
where BitPatternSource == UnsignedSelf {}
protocol SignedBitPattternInitializable: BitPattternInitializable, PairedUnsignedInteger
where BitPatternSource == SignedSelf {}
extension UInt: PairedUnsignedInteger { typealias SignedSelf = Int }
extension UInt8: PairedUnsignedInteger { typealias SignedSelf = Int8 }
extension UInt16: PairedUnsignedInteger { typealias SignedSelf = Int16 }
extension UInt32: PairedUnsignedInteger { typealias SignedSelf = Int32 }
extension UInt64: PairedUnsignedInteger { typealias SignedSelf = Int64 }
extension Int: PairedSignedInteger { typealias UnsignedSelf = UInt }
extension Int8: PairedSignedInteger { typealias UnsignedSelf = UInt8 }
extension Int16: PairedSignedInteger { typealias UnsignedSelf = UInt16 }
extension Int32: PairedSignedInteger { typealias UnsignedSelf = UInt32 }
extension Int64: PairedSignedInteger { typealias UnsignedSelf = UInt64 }
extension UInt: SignedBitPattternInitializable {}
extension UInt8: SignedBitPattternInitializable {}
extension UInt16: SignedBitPattternInitializable {}
extension UInt32: SignedBitPattternInitializable {}
extension UInt64: SignedBitPattternInitializable {}
extension Int: UnsignedBitPattternInitializable {}
extension Int8: UnsignedBitPattternInitializable {}
extension Int16: UnsignedBitPattternInitializable {}
extension Int32: UnsignedBitPattternInitializable {}
extension Int64: UnsignedBitPattternInitializable {}
protocol UnsignedHalfWidthInitializable: UnsignedInteger, FixedWidthInteger {
associatedtype UnsignedHalfWidth: FixedWidthInteger
init(high: UnsignedHalfWidth, low: UnsignedHalfWidth)
}
extension UnsignedHalfWidthInitializable {
init(high: UnsignedHalfWidth, low: UnsignedHalfWidth) {
self.init(littleEndian: Self(high) << UnsignedHalfWidth.bitWidth | Self(low))
}
}
protocol SignedHalfWidthInitializable: UnsignedBitPattternInitializable {
associatedtype UnsignedHalfWidth: UnsignedInteger, FixedWidthInteger
init(high: UnsignedHalfWidth, low: UnsignedHalfWidth)
}
extension SignedHalfWidthInitializable {
init(high: UnsignedHalfWidth, low: UnsignedHalfWidth) {
let unsignedPromotedHigh = UnsignedSelf(high)
let unsignedPromotedLow = UnsignedSelf(low)
let unsignedLittleEndian = unsignedPromotedHigh << UnsignedHalfWidth.bitWidth | unsignedPromotedLow
let signedLittleEndian = Self.init(bitPattern: unsignedLittleEndian)
self.init(littleEndian: signedLittleEndian)
}
}
extension UInt16: UnsignedHalfWidthInitializable { typealias UnsignedHalfWidth = UInt8 }
extension UInt32: UnsignedHalfWidthInitializable { typealias UnsignedHalfWidth = UInt16 }
extension UInt64: UnsignedHalfWidthInitializable { typealias UnsignedHalfWidth = UInt32 }
extension Int16: SignedHalfWidthInitializable { typealias UnsignedHalfWidth = UInt8 }
extension Int32: SignedHalfWidthInitializable { typealias UnsignedHalfWidth = UInt16 }
extension Int64: SignedHalfWidthInitializable { typealias UnsignedHalfWidth = UInt32 }
assert(UInt16(high: 0x12 as UInt8 , low: 0x34 as UInt8 ) == 0x1234 )
assert(UInt32(high: 0x1234 as UInt16, low: 0x5678 as UInt16) == 0x1234_5678 )
assert(UInt64(high: 0x1234_5678 as UInt32, low: 0x90AB_CDEF as UInt32) == 0x1234_5678_90AB_CDEF )
assert( Int16(high: 0x12 as UInt8 , low: 0x34 as UInt8 ) == 0x1234 )
assert( Int32(high: 0x1234 as UInt16, low: 0x5678 as UInt16) == 0x1234_5678 )
assert( Int64(high: 0x1234_5678 as UInt32, low: 0x90AB_CDEF as UInt32) == 0x1234_5678_90AB_CDEF )