シフトショック
画像のビット列をプログラムで扱ってる暦数年のつもりだったんですが,今朝とんでもないことに気づきました.ものすごく精神的ショック.32ビットのピクセルA, B, Cに対するビットシフト操作についてなんですが,
DWORD A = 0x12345678; DWORD B = 0x9ABCDEF0; DWORD C = ( A << 8 | 0xFF000000 ) | B >> 24 );
これの結果,Cは0xFF56789Aになります.で,ちょっと書き換えます.
BYTE* a = &A; BYTE* b = &B; DWORD c = 0xFF000000 | ( a[2] << 16 ) | ( a[3] << 8 ) | b[0];
これで同じ結果になる.そう思ってました.DWORDをBYTEで区切って,a[2] = 0x34,a[3] = 0x56にしようという目論見です.でも違うんですね.現実はa[2] = 0x56,a[3] = 0x34,b[0] = 0xF0なので,cが0xFF5634F0になってしまいます.Aはメモリ空間上には78563412と入っているわけで,BYTEが指すと逆になってしまうわけですね.普段バイナリエディタで覗いてるときは普通に理解してるのに,このケースだけ理解できてませんでした.つまりこうなると.
DWORD A = 0x12345678; BYTE* B = &A; assert( B[0] == 0x78 ); assert( B[1] == 0x56 ); assert( B[2] == 0x34 ); assert( B[3] == 0x12 ); A <<= 8; assert( B[0] == 0x00 ); assert( B[1] == 0x78 ); assert( B[2] == 0x56 ); assert( B[3] == 0x34 );
左シフトしてるつもりなのに,バイト配列になると右シフト.ちなみにこれは脳内計算なので実際にテストしてません.もし外れてたら逆に安心なわけですけど.