発生した問題

 パソコン用のアプリケーション・ソフトウエアを長年開発してきたPさんが,ある開発プロジェクトで,音響機器のオーディオ・ファイルを生成する組み込みソフトウエア・モジュールを設計することになりました。オーディオ・ファイルにはパソコンでも取り扱いができるフォーマットを採用していたため,Pさんは設計したモジュールの単体テストをすべてパソコン上で行い,結合テストに臨みました。

 ところが,このモジュールをターゲット・システムに組み込んでオーディオ・ファイルを生成し,パソコンに取り込ませようとしたところ,ファイルとして全く認識できないことが判明しました。

原因と対策

 Pさんが担当したモジュールは,上位のモジュールから指示されるオーディオ・データのサイズや属性を,ファイルのヘッダ情報としてメモリ上に用意したバッファ領域に格納します。さらに,別のモジュールが生成するオーディオ・データとともに,音響機器に内蔵されたHDDへデータが転送されることになっていました(図10-1)。設計したモジュールをパソコン上のシミュレータでデバッグすると,32ビットで表現されるオーディオ・データのサイズ情報やその他の属性情報などすべてが,メモリ上にオーディオ・ファイルの仕様で規定されているように並んでいることが確認できました。

 ところが同じモジュールをターゲット・システムに組み込んで,デバッガを使ってバッファ領域をダンプしてみると,各アドレスの数値の並び順が違うことが分かりました。例えばサイズ情報を表す32ビットのデータが0x00123456だった場合,図10-2のようにデータが並んでいました※1。パソコンのシミュレータでは,メモリのアドレスが若い順に0x56,0x34,0x12,0x00と並んでおり,ヘッダ情報の仕様通りでしたが,ターゲット・システムのメモリ上には0x00,0x12,0x34,0x56と並んでいました。つまりヘッダ情報のすべてのデータについて,メモリ上の数値の並び順がバイト単位で逆だったのです。

 パソコンのアプリケーション・ソフトウエアを開発してきたPさんは,メモリ上に格納されるデータの数値の並び順がLSB(least significant bit,最下位ビット)側から並んでいるのが当たり前と思っていたため,なぜターゲット・システムではMSB(most significant bit,最上位ビット)側からデータが並んでしまうのか,理解できていませんでした。そして,このことを開発チームのミーティングで相談すると,すぐに「エンディアン※2」の違いを指摘されました。

 実は音響機器の開発チームでは,製品シリーズを通してあるメーカーのマイコンを使用しており,メモリ・インタフェースには米Motorola, Inc.の半導体部門(現米Freescale Semiconductor, Inc.)が開発した68系のマイコンと互換性のあるビッグ・エンディアンを採用していました。これに対して,ほとんどのパソコンには米Intel Corp.の86系のマイコンが搭載されており,メモリ・インタフェースにはリトル・エンディアンが採用されています。従って,Pさんがパソコンを使ってモジュールのテストを行った場合と,開発中の音響機器のターゲット・システム上でモジュールを動作させた場合とでは,同じプログラムの書き方をしても,メモリ上に配置されるデータの並び方が逆になるのです(図10-3)。

 Pさんは他のモジュールを参考にして,データをメモリに格納する際に図10-4のようなマクロ定義を利用し,コンパイル時にシステムのエンディアンに応じてコンパイル・スイッチを使い分けることで,この問題を解決しました。

技術者必修の基本

 エンディアンの違いは,マイコンの内部でデータの受け渡しが完結する場合には,ほとんど意識する必要はありませんが,システムの外部とメモリ・インタフェースを介して16ビットや32ビットのデータを受け渡しする際には大変重要な意味を持ちます。また,外付けROMなどにプログラムを格納する場合にも,マイコンのエンディアンに合わせた形式で書き込む必要があります。

 エンディアンは基本的な知識ですが,今回のようなミスは実は結構発生しています。例えば,ベテランでもデータベースなどを使用しない開発者は,扱うデータの互換性を意識する必要があまりないため,今回のようにエンディアンを間違ってしまうことがあるようです。また新人技術者は,単一モジュールの設計が実務の中心である場合が多いため,マイコン内部で使用されるデータにだけ着目する習慣がついてしまうこともミスを引き起こす原因になります。

 使用するマイコンのエンディアンを理解し,データを取り扱う必要があるのと同時に,ソフトウエアを複数の製品で再利用するためには,エンディアンの違いを吸収できるプログラミングを行っておくことも大切です。

※10xは,続く数字が16進数という意味。16進数の00123456は,2進数では「00000000000100100011010001010110」になります。

※2エンディアン=複数バイトのデータの格納方式。例えばマイコンからストレージやメモリへの転送を行なうときに最上位のバイトから転送する方式を「ビッグ・エンディアン」(68系マイコンなどが採用),最下位のバイトから転送する方式は「リトル・エンディアン」(86系マイコンなどが採用)と呼びます。