🦁
SwiftでBigEndianとLittleEndian処理
最近RTMPクライアントライブラリ作っていて、そこでrtmpサーバ送信時に一部のデータをBigEndianで送信する必要があって、あまり詳しくなかったので、調査してまとめた。
BigEndianとLittleEndianとは
コンピュータの内部で数値を表現する方法の2つの方式で、BigEndianは、数値の上位バイトを先頭に配置する方式であり、LittleEndianは、数値の下位バイトを先頭に配置する方式です。
Swiftでは、BigEndianとLittleEndianのデータ型を用意しています。BigEndianの場合は、Data()クラスのbigEndianプロパティを使用して、LittleEndianの場合はData()クラスのlittleEndianプロパティを使用して変換できます。
BigEndian
下の表はUInt32の表示で、4バイト、BigEndianになっています。
Byte: 0 1 2 3
+--------+--------+--------+--------+
Value: | 0x12 | 0x34 | 0x56 | 0x78 |
+--------+--------+--------+--------+
UInt32をBigEndian値に変換する
let value: UInt32 = 305419896 // 0x12, 0x34, 0x56, 0x78
var bigEndianValue = value.bigEndian
assert(Data([0x12, 0x34, 0x56, 0x78]) == Data(bytes: &bigEndianValue, count: MemoryLayout<UInt32>.size))
BigEndian値からUInt32変更
DataのbigEndian使う。
let data = Data([0x12, 0x34, 0x56, 0x78])
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }.bigEndian
assert(value == 305419896)
もしdataがbigEndian値で確定な場合はdataのreversed使って順番逆転されてもいい。
let data = Data([0x12, 0x34, 0x56, 0x78])
let reverseData = Data(data.reversed())
let value = reverseData.withUnsafeBytes { $0.load(as: UInt32.self) }
assert(value == 305419896)
LittleEndian例
下の表はUInt32の表示で、4byte、littleEndianになっています。
Byte: 0 1 2 3
+--------+--------+--------+--------+
Value: | 0x12 | 0x34 | 0x56 | 0x78 |
+--------+--------+--------+--------+
UInt32からlittleEndian値変更
UInt32などはlittleEndianで、変換する必要がない
var value: UInt32 = 305419896 // 0x12, 0x34, 0x56, 0x78
var littleEndianValue = value.littleEndian
assert(Data([0x78, 0x56, 0x34, 0x12]) == Data(bytes: &value, count: MemoryLayout<UInt32>.size))
assert(Data([0x78, 0x56, 0x34, 0x12]) == Data(bytes: &littleEndianValue, count: MemoryLayout<UInt32>.size))
littleEndian値からUInt32変更
デフォルトがlittleEndianなので、変換する必要がない
let data = Data([0x78, 0x56, 0x34, 0x12])
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
assert(value == 305419896)
注意
BigEndianとLittleEndianはバイトの配列順番なので、もし1バイトの場合は変換する必要がない。
BigEndian値とLittleEndian値は同じ値になります。
let value: UInt8 = 0x01
let bigEndianValue = value.bigEndian
let littleEndianValue = value.littleEndian
assert(bigEndianValue == littleEndianValue)
Discussion