先日の記事 id:Nabetani:20070529:p2 の補足を少々。
で。
public class Test1 { public static void main(String[] args) { byte i8=0x12; i8<<=8; System.out.printf( "8bit : %x\n", i8 ); short i16=0x1234; i16<<=16; System.out.printf( "16bit : %x\n", i16 ); int i32=0x12345678; i32<<=32; System.out.printf( "32bit : %x\n", i32 ); long i64=0x1122334455667788L; i64<<=64; System.out.printf( "64bit : %x\n", i64 ); } }
という、先日のソースと大差ないもの(printf が使えることに気づいた!)を用意してみた。
出力結果は
8bit : 0
16bit : 0
32bit : 12345678
64bit : 1122334455667788
となる。
私なりに解説――あんまり自信がないけど――しておくと。
たとえば byte の場合。
シフトの前に int に昇格する。
昇格した int をシフトする。今回の例では 0x1200 になる。
その結果を byte に代入するわけだが、左辺が byte、右辺に相当する値が int なので精度が失われる。
精度が失われる 整数→整数 変換は本来エラーなので、
i8 = i8<<8;
と書くとエラーになるんだが、 <<= のような演算子の場合はエラーにならない。
というわけで、上述のような結果になる。
#ということは知っていたんだが、int を 32bit ずらしたときにどうなるのかは知らなかった。
int や long をその bit数以上シフトしたときに 0 になるような仕様にしておけば自然な結果になったのにと思う。
とはいえ、この手の罠は、C/C++ に比べると格段に少ないと思う。