K&Rを読もう(31) 演習 2-6 - 2-8 ビット結合
この演習問題しんどかった。インラインアセンブラで死にそうに・・・。
演習 2-6
位置pから始まるnビットのyの右端のnビットにセットし,他のビットをそのままにしたxを返す関数setbits(x,p,n,y)を書け。
図にしてみる
setbits(0x55, 4 , 3, 0xFF)を例にする。
p 76543210 x = 01010101 y = 11111111
位置pの4,3,2を結合して
010 111 01
というビット列を作る。
- pが位置。0から始まる。
- nが個数。1から始まる。
なので要注意。
方針
まず、マスクをずらしながら作る。
11111111 << 3 11111000 反転 00000111 << 4 - 3 + 1 00011100
x,yにマスクをかけて、or演算を用いて、結合する
010 000 01 | 000 111 00 = 010 111 01
という感じ。
ソース
#include <stdio.h> #include <stdlib.h> #define dump(type, bin) \ do { \ int i; \ for (i = sizeof (type) * 8 - 1; i >= 0; i--) \ putchar('0' + ((bin) >> i & 0x01)); \ puts(""); \ } while (0) unsigned char setbits(unsigned char x, int p, int n, int y); int main(void) { dump(unsigned char, setbits(0x55, 4 , 3, 0xFF)); return EXIT_SUCCESS; } unsigned char setbits(unsigned char x, int p, int n, int y) { unsigned char mask = ~(~0 << n) << (p - n + 1); return x & ~mask | y & mask; }
マスク作りに手間取った。
ビット反転ってステキ。
演習 2-7
xの任意範囲をビット反転。
unsigned char invert(unsigned char x, int p, int n) { unsigned char mask = ~(~0 << n) << (p - n + 1); return x & ~mask | ~x & mask; }
2-6をクリアすれば簡単。
演習 2-8
右ビットローテート
unsigned char rightrot(unsigned char x, int n) { return x >> n | x << sizeof (unsigned char) * 8 - n; }
アセンブリ使った方がいい。
演習 2-8のインラインアセンブリで
unsigned int ror(unsigned int x, unsigned int n) { asm ( "movl %1, %%edx;" "movb %2, %%cl;" "rorl %%cl, %%edx;" "movl %%edx, %0;" : "=m" (x) : "m" (x), "m" (n): "%edx", "%cl"); return x; }
(まんま載ってたのでほぼコピペ)
まとめ
- unsignedとsignedでは動作が違うので要注意。
- ビット演算はよく使うので体に叩き込んでおこう。
(使わないって・・・)