0x12345678
このデータをストアすると、各エンディアンで以下のようにメモリ上に保存されます。
| Address | Little | Big |
| 0000 | 78 | 12 |
| 0001 | 56 | 34 |
| 0002 | 34 | 56 |
| 0003 | 12 | 78 |
x86のようなリトルエンディアン環境でビッグエンディアンで32bit値をストアしたい場合、僕がパっと思いつくのは以下の2つの方法です。
1. Byteサイズのポインタを使ってコピー
void store_be(DWORD data, void* pw)
{
BYTE* pr = (BYTE*) &data;
BYTE* pwb = (BYTE*) pw;
pwb[0] = pr[3];
pwb[1] = pr[2];
pwb[2] = pr[1];
pwb[3] = pr[0];
}
2. Big Endianへ変換して格納
#define CONVERT_ENDIAN(d) ((((d) << 24) & 0xff000000) | (((d) << 8) & 0x00ff0000) | (((d) >> 8) & 0x0000ff00) | (((d) >> 24) & 0x000000ff))
void store_be(DWORD data, void* pw)
{
*((DWORD*) pw) = CONVERT_ENDIAN(data);
}
ここからが本題です。
問題は任意のビット長のデータを任意のビット位置から配置する場合です。
例えば0x123という有効ビット長が12bitのデータを各エンディアンで先頭バイトから詰まって
ゆくように格納する場合はどうなるでしょう?
メモリイメージで以下のように格納される場合です。
| Address | Little | Big |
| 0000 | 23 | 12 |
| 0001 | *1 | 3* |
※ ‘*’は未使用
このようにリトルエンディアンとビッグエンディアンでは単にバイトオーダーが違うだけでは
なくビット配置も異なります。
ビット走査(?)としては
・リトルエンディアンでは0->7(1byte目)8->15(2byte目)…
・ビッグエンディアンでは7->0(1byte目)15->8(2byte目)…
このことからわかるようにリトルエンディアンでは開始ビット位置+ビットサイズ-1で末尾ビット
位置を求めることができますが、ビッグエンディアンではそんなに単純にはできません。
このような場合、ビッグエンディアンのビット走査による位置の変化をリトルエンディアンと同じようにしてしまえば計算が楽になります。
つまり7->0->8->15のようなビット位置進行を0->7->8->15になるようにすれば良いのです。
これはビット位置を以下の変換式で変換してから計算することで可能です。
#define CONVERT_POS(n) (((n) | 7) - ((n) & 7))
上記の例でいえば7bit目(※ビッグエンディアンでは7bit目が最初のビットになる)から12bitの領域の末尾ですから、
CONVERT_POS(CONVERT_POS(7) + 12 ? 1);
これで末尾位置12を計算で求める事が出来ます。
このマクロと先のエンディアン変換マクロを併用することで任意位置から配置されるビッグエンディアンデータをマスクデータを含め比較的容易に作成することが出来ます。ただし、計算に用いている型のサイズを超えるデータを扱う場合や、境界を跨ぐ位置にデータが配置される場合は当然2回以上の計算が必要になりますが…