C言語入門::付録 ビット演算
マイコン用のプログラムでは,変数の特定ビットに対する演算が必要なことが多々あります.
二進法
コンピュータが扱えるのは,本来「0」と「1」だけです.そのため,変数の値も二進法で記録されています.
たとえば,「20」を二進法で表すと「10100」です.
論理演算
ビット演算の基本となる論理演算の説明です.論理演算とは真偽値(「0」と「1」のみ)を使った計算です.
AND(論理積)
C言語での記号は「&」です.
a | b | a&b |
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
a,b の両方が「1」ならば「1」.
OR(論理和)
C言語での記号は「|」です.
a | b | a|b |
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 1 |
どちらかが「1」ならば「1」.
NOT(反転)
C言語での記号は「~」です.
a | ~a |
0 | 1 |
1 | 0 |
「0」と「1」が反転する.
XOR(排他的論理和)
C言語での記号は「^」です.
a | b | a^b |
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
一方のみが「1」のときに「1」.
C言語での使い方
普通の加減乗除等の演算子と同じように使えます.
x = 142 | 98;
C言語では複数ビットをまとめて扱います.例えば,char型の値の演算では,8個の 0 または 1 の数値に対して同時に演算します.
142 | 98を計算してみましょう.
二進法で表記すると, 10001110 | 01100010 です.
筆算風に計算すると,
10001110 | 01100010 -------------- 11101110
となり,「11101110」が求まります.これは,10進表記した「238」と同じです.
つまり,上記の文のあとで,xの内容を表示すると,238になっているはずです.
シフト
指定しただけ,ビットをシフトします.
右シフト(>>) と 左シフト(<<)があります.演算時のビット数からはみ出た部分は捨てられます.
例:123 >> 3
01111011 >> 3 = 00001111
となって,15になります.
使用例
nビット目を取り出す
nビットシフトしてから,最下位ビットのみを取り出せばいいわけです.
Y = (X>>n)&1;
nビット目が0かどうか判定する
上のnビット目を取り出す例でもいいのですが,nが定数のときは,
if (X & (1<<n)) { ~ }
と書くと,(1<<n)も定数になり,ビットシフトが一つ減るので処理は速いです.
変数の特定ビットを1にする
変数の特定のビットを1にしたいとします.
X |= 0x07;
この例は,Xの下位3ビットを1にします.0x07は下位3ビットが1の整数です.これとXの論理和をとると,下位3ビットが1で,他のビットはXと同じです.さらに,Xに代入するので,Xの下位3ビットが1になり,他は変化しません.
X= abcdefgh (a~hは0または1) | 00000111 -------------- abcde111
ここで,重要なのは,b={0,1}のとき
- b|0 = b
- b|1 = 1が成り立つことです.
変数の特定ビットを0にする
X &= ~0x07;
この例は,Xの下位3ビットを0にします.まず,「0x07」は二進数に直すと「0b00000111」なので,下位3ビットが「1」になっている数値です.これを「~」で反転すると「0b11111000」という,下位3ビットのみが「0」になっている数値になります.これとXのANDをとると,下位3ビットは0で他はXのビットがそのままの数値になります.「&=」になっているので,これをXに代入します.
・反転 ~ 00000111 -------------- 11111000 ・AND X= abcdefgh (a~hは0または1) & 11111000 -------------- abcde000
ここで,重要なのは,b={0,1}のとき
- b&0 = 0
- b&1 = bとなっていることです.
ビット演算の利点
ビット演算の利点の一つは,速度が速いことです.多くのコンピュータで乗算や除算は数クロック~数十クロックかかりますが,ビット演算は1クロックで実行できます.
2^n倍したいときは,シフトを使うと高速です.「x*8」よりも,「x<<3」の方が速いです.
さらに,三倍したいとき等は,
((x<<1) + x)
と書くと,1回のシフトと,加算に分解できます.
と,ここまで書いてなんですが,最近のコンパイラはある程度の最適化をやってくれるのであまり意味はありません.それよりも,まずはアルゴリズム(計算手法)を最適化しましょう.AVRの乗算は(8ビットですが)速いので,あまり気にすることは無いと思いますし….
それよりは,マイコンでのプログラムの場合,メモリ効率の方が重要です.そのために,変数単位ではなくて,変数の特定のビットに意味を持たせることが多いです.こういうときは,ビット演算を使うほかはありません.
この文書の履歴
- 2006-08-06 とりあえず書く
- 2007-07-02 少し説明を追記