はじめに
学校で教科書として使っているCQ出版社の「組み込みソフトウェア開発スタートアップ」(デザインウェーブマガジン編集部 編)という本があるのですが、この本の50ページに「シフト演算だけで値を読み出す場合」として以下のようなサンプルコードが記されています。
# define bit(x, n) ((x << (8 * sizeof(int) - n - 1)) >> (8 * sizeof(int) - 1))
使い方としては、xというビット列からn番目だけを抜き取って読む、ということだと思います。しかしこれ、ぱっと見何をしているのかよくわからないので分解しつつ見ていきましょう、というお話です。
早速解読してみる
今回はxとして二進数で「10000101」を、nとして「2」を使ってみます。最も右のbitが0番目という風に数えます。
まずはここの部分から。sizeof(int)
をとりあえず4bytesと解釈しましょう。うちのclangがそういう仕様だったもので。
(x << (8 * sizeof(int) - n - 1))
こういうことなので、何bit左にシフトすべきか計算してみましょう。
8 * sizeof(int) - n - 1 = 8 * 4 - 2 - 1 = 29
ふむなるほど。ということはxは左に29bitシフトされて、こんな感じになります。縦棒から右がシフトされた分です。桁数はsizeof(int)の桁数で固定されますので、今回の場合全体として4bytes=32bitとなります。つまり、それ以上の桁はあふれていってしまうわけですね。
101|00000000000000000000000000000
では次の部分を。
(8 * sizeof(int) - 1)
これを計算した分だけ右にシフトすればいいわけですね。となると
8 * sizeof(int) - 1 = 8 * 4 - 1 = 31
ですね。改めて右に31bitシフトしてみましょう。今度は縦棒から左がシフトされた分です。
0000000000000000000000000000000|1
確かに特定のbitを読み取ることができることができました。しかしよくこんなトリッキーな計算方法思いつきますね...
int型の大きさは処理系によってまちまちです。しかしあくまで整数値の読み出しなので、sizeof演算子を使ってどんな環境でも動くようにしてあるんですね。恐れ入りました...