・ビットシフト(>>)には算術シフトと論理シフトがある。
・算術シフトは負数をシフトすると左側が1で埋まる (Arithmetic shift)
・論理シフトは負数をシフトすると左側が0で埋まる (Logical shift)
・どちらの挙動をするかは処理系依存
ということで、強制的に論理シフトしたい時は工夫する必要がある。
unsignedにキャストする。以下C++のコード。
#include <iostream> //表示のためにbitsetを使う #include <bitset> int main() { char val = -40; char S = val; char A = val >> 2;//処理系依存 VC++2019では算術シフト char L = static_cast<unsigned char>(val) >> 2;//論理シフト std::bitset<8> Sdisp(S); std::bitset<8> Adisp(A); std::bitset<8> Ldisp(L); std::cout << "source : " << Sdisp << " == " << static_cast<int>(S) << '\n'; std::cout << "not cast and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n'; std::cout << "cast to unsigned and >>2 : " << Ldisp << " == " << static_cast<int>(L) << '\n'; getchar(); return 0; }
同じ事を関数化するなら以下のような感じになる。
#include <iostream> #include<type_traits>
//! @brief 論理右シフト //! @param [in] val 右シフトする値 //! @param [in] shift 右シフトするビット数 //! @return val >> shift template<typename T> inline auto logical_right_shift(const T val,const int shift) { return static_cast< typename std::make_unsigned<T>::type>(val) >> shift; }
int main() { char val = -40; char S = val; char A = val >> 2;//処理系依存 VC++2019では算術シフト char L = logical_right_shift(val, 2);//論理シフト std::bitset<8> Sdisp(S); std::bitset<8> Adisp(A); std::bitset<8> Ldisp(L); std::cout << "source : " << Sdisp << " == " << static_cast<int>(S) << '\n'; std::cout << "not cast and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n'; std::cout << "logicalrightshift 2 : " << Ldisp << " == " << static_cast<int>(L) << '\n'; getchar(); }
負数の算術シフトが処理系依存とは。流石Cと言わざるを得ない。