2021年12月25日
川俣晶の縁側ソフトウェアnew_C#入門・全キーワード明快解説! total 754 count

~/&/^/|/<</>>演算子: ビット操作は難易度は高いが効率も高い

Written By: 川俣 晶連絡先

この章のテーマ §

 ~/&/^/|/<</>>演算子について学びます。ビットに関する知識がないと分かりにくい原始的な機能ですが、理解すると高効率のソースコードを記述できます。

前提知識 §

Console.WriteLineメソッド, 文字列の基礎, 変数の基礎, int型

解説 §

 整数の値を、数値ではなく数値を表現するビットを単位として扱う低レベルの演算子があります。

 こういう演算子は、理解するためのハードルは高いのですが、使えると便利なので存在しています。

 サンプルソースには3と5という数値が書かれていますが、それぞれ、00000000000000000000000000000011、00000000000000000000000000000101という2進数表記のビットの並びを表現しています。

 ~演算子はビットを反転します。0が1に、1が0になります。00000000000000000000000000000011は11111111111111111111111111111100になります。10進数に直すととてつもなく大きな値になります。サンプルソースの実行結果の~a=4294967292という結果はとてつもなく大きな値になったことを示します。

 &はAND演算子です。これは双方が1なら結果が1になる演算子です。011と101なら結果は001(10進数では1)になります。

 |はOR演算子です。これは片方が1なら結果が1になる演算子です。011と101なら結果は111(10進数では7)になります。

 ^はXOR演算子です。これはどちらが1なら結果が1になる演算子です。011と101なら結果は110(10進数では6)になります。

 <<は左シフト演算子です。右側の値分だけビットを左側にずらします。011なら結果は110(10進数では6)になります。

 >>は右シフト演算子です。右側の値分だけビットを右側にずらします。011なら結果は001(10進数では1)になります。

罠の数々 §

  • 列挙型の定義をビットマスクで使用する場合は、&や|演算子の知識が不可欠である。難易度は高いが、いつかの時点で乗り越えるべきハードルである。
  • &&演算子、||演算子と&演算子、|演算子は似ているところもあるが、機能も利用目的も異なることに注意
  • この解説では煩雑になるので負数の表現に触れていない。そのため、サンプルソースでも、符号なし整数のuint型を使用している。C#で使用している負数表現は二の補数というもので、最上位ビットが1だと負数になり、全てのビットが1だと-1を表す表現方法である

参考リンク §

ビットごとの演算子とシフト演算子 (C# リファレンス)

サンプルソース: bitsOperators §

uint a = 3;

uint b = 5;

Console.WriteLine($"~a={~a}");

Console.WriteLine($"a & b={a & b}");

Console.WriteLine($"a | b={a | b}");

Console.WriteLine($"a ^ b={a ^ b}");

Console.WriteLine($"a << 1={a << 1}");

Console.WriteLine($"a >> 1={a >> 1}");

実行結果 §

~a=4294967292

a & b=1

a | b=7

a ^ b=6

a << 1=6

a >> 1=1

リポジトリ §

https://github.com/autumn009/CSharpPrimer2

練習問題 §

 数値を2倍するのと、1bit左シフトするのは同じ結果になると気付いた。

 *2のかわりに、<<1と書いて良いのだろうか。

 演算子の優先順位の問題は問わないとして良いか悪いか考えてみよう。

  1. 良い
  2. 条件付きで良い
  3. お勧めはしない

[[解答]]

単行本情報