0xFF00 >> 8 == 255
なのはなんとなく見た目通りだから良いけど、
65280 >> 8 == 255
なのは違和感を感じる。なぜなら、65280はビッグエンディアンな環境なら0xFF00としてそのままメモリ上に表現されると思うけど、リトルエンディアンな環境ならメモリ上では0x00FFとして表現されていると思うから、8ビット右シフトしたら0になって欲しい気がする。
でも、実際にArduinoで動かしてみてSerial.printすると、そうはならない。
ここで0xFF00 == 65280
とすると真が返っている。つまり、0xなんちゃらはビッグエンディアンっぽい表記をした後に内部的にリトルエンディアンに変換されていて、>>は右ビットシフトのつもりだったけどリトルエンディアンな環境だと実は左にビットシフトしているのかも知れない。
これまでビッグエンディアンな環境でしか作業をしてこなかったし、特に詳しく調べることもなかったのだけど、内部的なエンディアンとは別に記述は全部ビッグエンディアンっぽい感じにしよう、みたいな感じになっているのかも知れない。
ちなみに、実はArduinoがビッグエンディアンだった!というオチは無いっぽくて、バイト列を受け取ったAndroidは(というかJVMが?)ビッグエンディアンなのでリトルエンディアンをビッグエンディアンに変換して受け取っている。
こういうのってどこで調べれば良いんだろう。面倒そうなので調べる気が起きない。
long型のデータを頑張ってuint16_tの配列とかにぶつ切りにして突っ込んだりしていたらこういう疑問にぶち当たってわたわたしていた。
追記
以下のような意見をいただきました。
@shimobayashi 低レイヤーに詳しくないので私が何か言ってもあれですけど、ビットシフト演算は C とか Java 上でやってるんですよね? メモリ上に数値がどう表現されているか (エンディアンの問題) は、コンパイラ (?) が吸収してくれていると思うのです。
— nobuokaさん (@nobuoka) 12月 15, 2012
@shimobayashi 環境しらねぇけどコンパイラが解釈してくれてるんじゃないかな。
— かかっちさん (@kakashi__0912) 12月 15, 2012
@shimobayashi エンディアンを意識しないでコード書ける方が便利ですし。
— かかっちさん (@kakashi__0912) 12月 15, 2012
@shimobayashi 特に根拠は示せないので何とも言えませんが、コンパイラがエンディアンの差異を吸収してくれないと、普通の四則演算もちゃんとならないわけだし、ビットシフトもエンディアンを気にせず使えた方が私としては直観的だと思いますけどねー。 うーん。
— nobuokaさん (@nobuoka) 12月 15, 2012
@shimobayashi うーん、あまり心当たりはないなぁ。コンパイラの仕様書とかあればワンチャンぐらい。
— かかっちさん (@kakashi__0912) 12月 15, 2012
@shimobayashi あー、shimobayashi さんのエントリを読みなおして思ったんですが、0xFF00 というような表記にした場合ってただの基数 16 の数値だとみなされるので、0xFF00 >> 8 も 65280 >> 8 も同じものだと思っていいのですよ。
— nobuokaさん (@nobuoka) 12月 15, 2012
ビッグエンディアンっぽい方が便利、みたいな雰囲気です。
追記
@shimobayashi 遅レスだけど,エンディアンはメモリ上の格納方式なので,計算結果とか数値の表記には影響しないですよ.数値をバイト列としてアクセスするとか,エンディアンが違う環境にバイナリデータを渡す場合に考えればいいです
— Kosuke bnz Kawahira'さん (@binzume) 12月 15, 2012