鍋あり谷あり

テーマを決めずに適当に書いています。

私の知っているjava -- シフト演算補足

先日の記事 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++ に比べると格段に少ないと思う。