エンディアンの変換

macOS Swift

エンディアンの変換

macOS 10.15.7 / Xcode 11.3.1 / Swift 5.0

概要

エンディアンとは数値を表現するバイトの並びの違い、いわゆるバイトオーダーのことである。
数値(整数/浮動小数点数)は表現できる数の範囲に従って、1バイト、2バイト、4バイト、8バイトを単位としたメモリ領域に割り当てられ、それぞれの型が定義される。2バイト以上に割り当てられた領域はバイトの並び順のルールが 2種類あり、桁の大きい順にバイトを並べるビッグエンディアン方式と、桁の小さい順にバイトを並べるリトルエンディアン方式に分かれる。これは CPUの機種によって決まる。
実例として Int型の整数値 999999 のエンディアンの違いによる内部表現を示す。
数の並びからすると、大きい桁が左にくるビッグエンディアンの方が自然に見える。そのまま電卓にコピーすることができる。一方リトルエンディアンの並びは違和感があるが、数値計算を効率化できるというメリットがあるので、こちらを採用する CPUも少なくない。

エンディアンの変換が必要な場合

一般的には Swiftが扱うようなアプリケーションではエンディアンの違いを意識する場面はほとんどない。必要があればプログラム言語やライブラリがその差を吸収しているためである。しかし、アプリケーションが外部ファイルや通信データからバイトストリームを直接読み込み、操作する場合は意識しなければならない。
例えば、JPEGファイルのデータや TCP/IP通信のネットワークバイトオーダーはビッグエンディアンであるが、これをリトルエンディアンの PCに読み込むとき、あるいは PCで処理したデータを書き出すときエンディアンの変換が必要になる。

エンディアンの変換をサポートするクラス

本サイトの別の章では JPEGファイルの撮影情報から撮影日時、GPS情報を取得するアプリケーションについて記載している。アプリケーションの作成にあたっては整数値のエンディアンを変換する処理が鍵であったので、エンディアンの操作に関わる関数をクラスにまとめて利用した。汎用的に利用することもできるのでここで紹介したいと思う。

IntManagerクラス

機能

エンディアンを指定して Dataオブジェクトから整数を読み込む

Int型(8バイトまたは 4バイトの符号付き整数)の整数を抜き出す。整数の型により個別のメソッドを提供する。
読み込むことができる整数型と使用するメソッド
(注1) Int、UIntのバイト数は CPUの種類による
(注2) Int8、UInt8の 1バイト整数はエンディアンの変換はない
例題
ファイルに作成されたビッグエンディアン形式の 符号付整数(Int 64ビット)をリトルエンディアンのホストPC(Intel x64系 CPU)で読み込む。この場合、エンディアンの変換が必要。
データの内部表現:値 259(0x103)
IntManagerクラスの getIntメソッドは Dataオブジェクトの指定した位置から Int型の整数を抜き出す。必要であればエンディアンを指定する。本例では、ビッグエンディアンを指定し、読み込んだビッグエンディアンのデータをリトルエンディアンに変換している。
引数のエンディアンは、読み込もうとするデータのエンディアンを指定する。読み込まれたデータは、ホストPCのエンディアンに従ってリトルエンディアンかビッグエンディアンのいずれかになる。ここでは「ビッグエンディアン」指定して読み込んだ整数をホストPCのエンディアンに合わせてリトルエンディアンに変換している。なお、データとホストのエンディアンが同じなら内部的には何も行わない。
引数のエンディアンを指定しない場合は、ホストPCのエンディアンが指定されたものとする。

エンディアンを指定して整数を Dataオブジェクトに書き出す

整数を指定されたエンディアンに変換して Dataオブジェクトに書き出す。ジェネリクス関数なので整数の型に関わらず、メソッドは1種類である。関数が型を推論できるように、入力の整数は型を明示して宣言すること。(型を宣言しない場合 Intになる)
書き出すことができる整数
(上記、読み込むことができる整数型と同じ)
例題
整数 259をビッグエンディアンに変換してファイルに書き出す。書き出す整数の型に関わらず、メソッドは putInteger( ) である。