🦁

SwiftでBigEndianとLittleEndian処理

2023/03/19に公開

最近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