スポンサーリンク

| キーワード:

C/C++で負数の右論理シフト(>>)をする

概要

・ビットシフト(>>)には算術シフトと論理シフトがある。

・算術シフトは負数をシフトすると左側が1で埋まる (Arithmetic shift)

・論理シフトは負数をシフトすると左側が0で埋まる (Logical shift)

・どちらの挙動をするかは処理系依存

ということで、強制的に論理シフトしたい時は工夫する必要がある。

結論

unsignedにキャストする。以下C++のコード。

具体例1

#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;
}

具体例2(テンプレート)

同じ事を関数化するなら以下のような感じになる。

#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と言わざるを得ない。

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: