紙にビットを書き、一方の端からそれらを消去し、もう一方の端にさらに追加することを考えてください. 小学生と変わらず、10を掛けるときに小数点をずらします。
すべての C 関数はゼロをシフトインします。
そう
x = y << 3;
は、3 ビット左にシフトし、右側の新しいビットはすべてゼロであることを意味します。左側にあった 3 つのビットは、「ビット バケット」に入ります。
x = z >> 2
右側の 2 ビットを失い、左側に 2 つのゼロを追加します。
欠落している機能と、K&R 演習の目的を見つけることができます。世の中に出回っているプロセッサの種類の中には、C やその他の高水準言語よりもはるかに多くのシフト機能があります。
一方の端からシフトされたビットが他方の端にシフトされる回転機能があります。
したがって、この方法で 1 ビット右に回転した数値 0xD は 0xE になります。これは、最下位ビットが 1 であったため、1101 を右にシフトすると、右の 1 が左の 1110 の 1 になります。
場合によっては、ALUのキャリー ビットを回転させます。キャリー ビットに 0 があり、0xD を 1 ビット 0 1101 に回転すると、1 0110 が 0x6 になるとします。0 1011 をもう 1 回回転すると、0xB などが得られます。
なぜあなたが尋ねるキャリービットを回転させるのでしょうか? より大きな数の場合、4 ビット レジスタがあり、8 ビット シフトを実行したいとします。たとえば、各文字が bcde fghi のビットでa
あり、 がキャリー ビットで、他の 2 つの 4 つのグループが 4 ビット レジスタであるとします。キャリー e abcd fghi を介して左レジスタをローテーションすることから始め、キャリー i abcd efgh を介して右レジスタをローテーションします。かなりクール; 4 ビット シフト関数で 8 ビット シフトを実行しました。
開始する前にキャリー ビットをクリアした場合 (多くの場合、これに関する命令が存在するか、0+0 を追加するなど、そのビットをクリアすることが保証されている何かをいつでも実行できます)、次のようになります。
私は0bcd efgh
これは、64ビット数で動作する32ビット命令セットで言う場合、Cシフト関数が行うことと同じです。
プロセッサには、多くの場合、0 がシフトインされる C のようなシフトがあります。シフト abcd 左 1 は bcd0 を返し、シフト abcd 右 2 は 00ab を返します。
そして、これは最新のプロセッサを使用する若い人々にいくつかの問題を引き起こします...整数除算はプロセッサでサポートされており、単一のクロックサイクルで動作できるため、そのようなことを考えてください. 除算が行われる前、または除算が数十から数百のクロックであったとき、シフトは単一のクロックであり、代わりにシフトを使用して 2 の累乗または乗算をすべて実行していました。0b00001101 << 2 = 0b00110100 または 0x34. 0xD は 10 進数の 13 で、0x34 は 10 進数の 52 です。52 は 13 の 4 倍です。4 は 2 の 2 乗です。2 だけシフトすることは、4 を掛けることと同じです。
これは双方向に機能します。0x34 右シフト 2 は 0xD ですが、ここに問題があります。負の数になったら、4 0xFC を引いた数を取り、それを 2 で割ります。C 0xFC >> 1 を使用すると 0x7E になりますが、0x7E は +126 10 進数です。-4/2 = 126 はどのようになりますか?
問題は、C がゼロにシフトすることです。一部のプロセッサには、論理シフトとは異なる算術シフトがあることがわかります。算術シフトは最上位ビットを保持するため、0bQWER のような符号付き数値を使用している場合、その数値を算術的に右に 1 ビットシフトすると、0bQQwe が得られます。最上位ビットは次のビットにシフトし、元の場所にとどまります。
再び 0bQQQW にシフトします。ここで、算術左シフトは最下位ビットではなくゼロをシフトするため、左にシフトされた 0bQWER は 0bWER0 です。そして、それは理にかなっています。-4 左シフト 1 は 0xF8 で、-8 で、-4 かける 2 は -8 です。
そのため、一部のプロセッサには算術右シフトのみがあり、左シフトがないことがわかります。asl を指定できるものもありますが、アセンブル時にそれを lsl (論理左シフト) に置き換えます。同じ関数であっても、実際には別のオペコードを持っているものもあります。asl と asr と lsr があり、lsl がないものがあると思います。
紙と鉛筆を使って物事を理解するだけです。例として実数から始めて、次に抽象化します。右に 1 ビット回転させたいとし0x1234
ましょう。
0001001000110100 write out the bits
x0001001000110100 shift right one
0000100100011010 because this is a rotate fill in the new bit with the bit that fell off on the prior operation
右に 2 ビットシフトしたい
0000100100011010
xx0000100100011010
1000001001000110
Cで単一ビットの回転を行うにはどうすればよいですか?
unsigned int rotate_right_one ( unsigned int x )
{
unsigned int y;
y = x & 1; // Save the bit that is about to fall off the right
x >> = 1; // Logical rotate one bit
x |= y<<31; // This assumes that unsigned int is 32 bits.
return(x);
}
さらに回転するには、この関数を複数回呼び出すか、上記のマスクとシフトについて考え、それが複数のビットに対してどのように機能するかを考えます。
また、回転機能が 1 つしかないプロセッサーもあることに注意してください。たとえば、これについて考えてみてください。4 ビットのレジスタがあり、5 ビットをローテーションします。何を得るか?
abcd
bcda first rotate
cdab second
dabc third
abcd fourth
bcda fifth
左に 1 回回転すると、どのように見えますか?
abcd
bcda one bit left.
4 ビット レジスタの 5 つの右は、1 つの左 5-4=1 と同じです。asl のように、一部のプロセッサでは操作をコーディングできますが、アセンブラは回転量として nbits-shift を使用して、その操作を別の回転に置き換えます。
一部の人々にとって、論理ビット操作は理解するのがポインターと同じくらい難しいですが、それは基本的なものであり、それを学んで使用すれば、競合他社や周囲の人々よりもはるかに先を行くでしょう.
以下は、変数のビット数をカウントする例です。
for(count=0, r=1; r; r<<=1)
if(r&some_variable)
count++;
そのコード行を理解すれば、C と論理ビット演算の両方を学習するための順調な道のりです。