32

第 2 章のビット演算子に関するセクション (セクション 2.9) で、サンプル メソッドの 1 つがどのように機能するかを理解するのに苦労しています。

提供されるメソッドは次のとおりです。

unsigned int getbits(unsigned int x, int p, int n) {
    return (x >> (p + 1 - n)) & ~(~0 << n);
}

考え方は、指定された数値x に対して、位置pから始まるnビットを右から数えて返すというものです(右端のビットが位置 0 になります)。次の方法を考えます。main()

int main(void) {
    int x = 0xF994, p = 4, n = 3;
    int z = getbits(x, p, n);
    printf("getbits(%u (%x), %d, %d) = %u (%X)\n", x, x, p, n, z, z);

    return 0;
}

出力は次のとおりです。

getbits(63892 (f994), 4, 3) = 5 (5)

私はこれの一部を理解していますが、主に私が理解していないビット (しゃれは意図していません) のために、「全体像」に問題があります。

私が特に問題を抱えている部分は、補足部分です: ~(~0 << n). xを扱う最初の部分を取得したと思います。私が苦労しているのはこの部分 (そしてマスク) であり、実際にそれらのビットを取得するためにすべてがどのように組み合わされるかです。(コードと calc.exe を使用して結果をチェックすることの両方で、それが実行されていることを確認しました。バイナリ ビューがあることを神に感謝します!)

何か助けはありますか?

4

6 に答える 6

42

この例では 16 ビットを使用してみましょう。その場合、~0等しい

1111111111111111

このnビット (あなたの場合は 3) を左シフトすると、次のようになります。

1111111111111000

左側のs1が破棄され、0s が右側に供給されるためです。次に、それを再補完すると、次のようになります。

0000000000000111

nしたがって、これは数値の最下位部分で 1 ビットを取得する賢い方法です。

あなたが説明した「xビット」は、指定された数値(f994 = 1111 1001 1001 0100)を十分に右にシフトしたため、最下位3ビットが必要なビットになります。この例では、要求している入力ビットがあります。他のすべての入力ビットは.、最終結果にとって重要ではないため、マークされています。

ff94             ...........101..  # original number
>> p+1-n     [2] .............101  # shift desired bits to right
& ~(~0 << n) [7] 0000000000000101  # clear all the other (left) bits

ご覧のとおり、関連するビットが右端のビット位置にあります。

于 2008-10-13T13:59:08.803 に答える
13

最善の方法は、手で問題を解決することです。そうすれば、それがどのように機能するかを理解できます。

これは、8ビットのunsigned intを使用して行ったことです。

  1. 数値は 75 で、位置 6 から始まる 4 ビットが必要です。関数の呼び出しは getbits(75,6,4); になります。

  2. バイナリの 75 は 0100 1011 です

  3. したがって、最下位ビットから始まる 4 ビット長のマスクを作成します。これはこのように行われます。

~0 = 1111 1111
<<4 = 1111 0000
~ = 0000 1111

さて、私たちはマスクを手に入れました。

  1. ここで、数値から必要なビットを最下位ビットにプッシュして、バイナリ 75 を 6+1-4=3 だけシフトします。

0100 1011 >>3 0000 1001

これで、下位に正しいビット数のマスクがあり、下位に元の数から必要なビットがあります。

  1. だから私たちと彼ら
  0000 1001
& 0000 1111 ============ 0000 1001

したがって、答えは 10 進数の 9 です。

注:高次のニブルはたまたますべてゼロであるため、この場合はマスキングが冗長になりますが、最初の数値の値に応じて何でもかまいませんでした。

于 2008-10-13T14:57:26.313 に答える
6

~(~0 << n)n右端のビットがオンになるマスクを作成します。

0
   0000000000000000
~0
   1111111111111111
~0 << 4
   1111111111110000
~(~0 << 4)
   0000000000001111

結果を他の何かと AND すると、それらのnビットの内容が返されます。

編集:私がずっと使ってきたこのプログラマーの電卓を指摘したかった: AnalogX PCalc

于 2008-10-13T14:02:19.687 に答える
4

まだ誰も言及していませんが、ANSI C では~0 << n未定義の動作を引き起こします。

これは、~0が負の数であり、左シフトする負の数が定義されていないためです。

参照: C11 6.5.7/4 (以前のバージョンには同様のテキストがありました)

の結果E1 << E2E1左シフトされたE2ビット位置です。空いたビットはゼロで埋められます。[...] E1 に符号付きの型と負でない値があり、E1×2E2が結果の型で表現できる場合、それが結果の値です。それ以外の場合、動作は未定義です。

K&R C では、このコードは K&R が開発した特定のクラスのシステムに依存し、1符号付き数値の左シフトを実行するときにビットを単純に左にシフトします (また、このコードは 2 の補数表現にも依存します)。これらのプロパティを共有しないため、C 標準化プロセスではこの動作が定義されませんでした。

したがって、この例は歴史的な好奇心としてのみ興味深いものであり、1989 年以降 (それ以前ではないにしても) の実際のコードでは使用しないでください。

于 2016-05-11T13:26:39.137 に答える
2

例を使用して: int x = 0xF994, p = 4, n = 3; int z = getbits(x, p, n);

この一連の操作に焦点を当てる ~(~0 << n)

任意のビット セット (10010011 など) に対して、表示したいビットのみをプルする「マスク」を生成します。10010011 か 0x03 ということで、xxxxx011 に興味があります。そのセットを抽出するマスクは何ですか? 00000111 sizeof int に依存しないようにしたいので、マシンに作業を任せます。つまり、バイト マシンの場合は 0 で始まり、ワード マシンの場合は 0x00 で、0x0000 などです。64 ビット マシンは 64 ビットまたは 0x0000000000000000 で表され

ます。 not" (~0) and get 11111111 get
right right (<<) shift by n and get 11111000
and "not" that and get 00000111

so 10010011 & 00000111 = 00000011
ブール演算の仕組みを覚えていますか?

于 2008-10-13T14:00:48.970 に答える
-2

原因でANSI C ~0 >> n未定義の動作

// 問題を引き起こす左シフトに関する投稿は間違っています。

unsigned char m,l;

m = ~0 >> 4; は 255 を生成しており、それは ~0 に等しいですが、

m = ~0; l = m >> 4; 次と同じ正しい値 15 を生成しています。

m = 255 >> 4;

~0 <<左シフトの負はまったく問題ありません

于 2018-02-23T00:36:49.460 に答える