2

私はビット演算にある程度精通していますが、この関数は頭を悩ませました。

void binary_print(unsigned int value) {
  unsigned int mask = 0xff000000;   // Start with a mask for the highest byte.
  unsigned int shift = 256*256*256; // Start with a shift for the highest byte.
  unsigned int byte, byte_iterator, bit_iterator;

  for (byte_iterator=0; byte_iterator < 4; byte_iterator++) {
    byte = (value & mask) / shift; // Isolate each byte.
    printf(" ");

    for (bit_iterator=0; bit_iterator < 8; bit_iterator++) {
      // Print the byte's bits.
      if (byte & 0x80) // If the highest bit in the byte isn't 0,
        printf("1");   // print a 1.
      else
        printf("0");   // Otherwise, print a 0.

      byte *= 2;       // Move all the bits to the left by 1.
    }
    mask /= 256;       // Move the bits in mask right by 8.
    shift /= 256;      // Move the bits in shift right by 8.
  }
}

この関数は、関数のビットフラグを受け取りopen()、適切なラベルを追加するdisplay_flags関数を使用して次の出力を生成します。

O_RDONLY : 0 : 00000000 00000000 00000000 00000000
O_WRONLY : 1 : 00000000 00000000 00000000 00000001
O_RDWR : 2 : 00000000 00000000 00000000 00000010
O_APPEND : 1024 : 00000000 00000000 00000100 00000000
O_TRUNC : 512 : 00000000 00000000 00000010 00000000
O_CREAT : 64 : 00000000 00000000 00000000 01000000
O_WRONLY|O_APPEND|O_CREAT : 1089 : 00000000 00000000 00000100 01000001 

出力を理解するのに問題はありませんが、実際のプロセスを理解していません。

  1. byte = (value & mask) / shift個々のビットをどのように分離しますか?
  2. if(byte & 0x80)「バイトの最上位ビットが0でない場合」を意味するのはなぜですか?
  3. これらの行はどのように:byte *= 2;mask /= 256;およびshift /= 256;ビットを移動し、なぜこの操作が重要なのですか?
4

6 に答える 6

11

byte = (value & mask) / shift1.個々のビットをどのように分離しますか?

maskは、常に 8 つの連続するビットが 1 に設定され、残りが 0 に設定されるビット パターンです (それは0xff000000、次になどで始まり0x00ff0000ます。そのため、 および のビットごとの および を取得するmaskvalue、 からのすべてのビットvalueが 0 に設定されます。で指定されたバイトに対応するmaskもので、その値を保持します。

shiftshiftマスキングを生き残った正確なビットで除算することによって、右端のビットになる対応する値に設定されます (質問 3 への回答を参照してください)。

したがって、はであり、その初期値は であり、その初期値はvalueであると仮定します。次にであり、最終結果はです。0xDEADBEEFmask0xff000000shift256*256*256value & mask0xDE0000000x000000DE

バイナリでは、例は次のようになります

value       = 11011110101011011011111011101111
mask        = 11111111000000000000000000000000
byte & mask = 11011110000000000000000000000000
result      = 00000000000000000000000001101111

2. なぜif(byte & 0x80)「バイトの最上位ビットが 0 でない場合」という意味ですか?

ここで、コード作成者はbyte8 ビット変数であると考えています。技術的にはより大きくなりますが、上位ビットはここでは使用されません。byteしたがって、著者が「最上位ビット」に言及するときは、右から 8 番目のビット (実際にはサイズが 1 バイトしかない場合に存在する最上位ビット) を考えてください。

ここで、バイナリで0x80あることに注意してください。10000000したがって、 を取得すると、「最高」(右から 8 番目) を除くbyte & 0x80すべてのビットが 0 に設定されます。bytefrombyte & 0x80の最上位ビットが 0 の場合byteは 0 であり、from の「最上位」ビットが 1 の場合は 0 より大きいbyte

3. これらの行はどのようにしてビットを移動し、この操作が重要なのですかbyte *= 2;?mask /= 256;shift /= 256;

2 の乗算は、ビットを 1 だけ左にシフトすることと同じです。たとえば、10012 進数の値 9 を考えてみましょう。2 を掛けると 18 になり、これは100102 進数です。

2 による除算と同様に、これは右への 1 シフトです。256 による除算は 2 による 8 除算に相当するため、256 による除算は 8 ビットの右シフトに相当します。これらの操作は、たとえば、値maskを から0xff000000に変更し0x00ff00000x0000ff00最後にに変更するために使用されます0x000000ff

フル機能の説明

この知識があれば、完全な関数が何をするかを見ることができます。外側のループでは、 にある 4 バイトをループし、value最も左のバイトから始まり、最も右のバイトで終了します。これは、現在のバイトをマスクして に格納することによって行いbyteます。

内側のループは、 に格納されている 8 ビットを処理しbyteます。常に右から 8 番目のビットを見て、それに応じて 1 または 0 を出力します。次に、ビットを左にシフトするため、2 回目の反復では、右から 7 番目だったビットが右から 8 番目になり、次のビットが出力され、8 ビットすべてが右から出力されるまで続きます。 -左の順序。

この関数を記述する別の方法は次のようになります。

for (int i = 31; i >= 0; i--) {
  if (value & (1 << i))
    printf("1");
  else
    printf("0");

  if (i % 8 == 0)
    printf(" ");
}

valueこれは、左から右の順序ですべてのビットを通過するだけです。この式は、右から 32 番目 (が 31 の場合) から始まり、右から 1 番目 (が 0の場合) で終わるvalue (1 << i)目的のビットを から選択します。valueii

于 2013-02-16T14:26:55.657 に答える
1

覚えておくべき最も重要なことは、bitwiseロジックは に対する操作の実行に依存していることbitsです。したがって、すべての意図と目的のために、ビット単位& (and)は 1 を法とする乗算であり、ビット単位は 1 を法と| (or)する加算です。これを確認する最も簡単な方法は、次の例です。

いくつかのバイトが0xF0あり、最上位ビットが設定されているかどうかを確認したい場合はand0x80. 何が起こるかは次のとおりです。

  11110000 = 0xF0
x 10000000 = 0x80
==========
  10000000 = 0x80

したがって、 の最上位ビット0xF0が実際に設定されていない場合、結果は0ではなく and になり0x80ます。2 進数を作成することにより、任意のビット位置またはビット位置のシーケンスでこれを行うことができます。たとえば、0x88 = 10001000これはバイトの最上位ビットと 4 番目のビットをチェックします。

バイナリで重要なことは、各位置が 2 の乗算であることに注意することです。だから00000001 = 1、その後00000010 = 2など00000100 = 4。つまり、掛け算 by2は左シフト ( <<) のようなものです。256 による除算は、8 による右シフト ( >>) です。これは、2 のべき乗で考えると最も簡単にわかります。2^8 = 256. したがって、各ビットはこれら2の の 1 つであるため、 の除算は2568 だけ右にシフトすることと同じです (指数/必要な 2 の数)。

于 2013-02-16T14:33:10.360 に答える
1

1) value & mask を使用すると、目的のバイトを除くすべてのバイトがゼロになります。それをシフトで除算すると、バイト 0 に移動します (個人的には >> 演算子を使用します)。

2) バイト & 0x80 は、最上位ビットを除くすべてのビットを削除します。0x80 は 2 進数で 10000000 で、1 ビット セットはバイトの最上位ビットと一致します。結果の値は 0 または 10000000 (16 進数 0x80) になります。IF は、最上位ビットが設定されている場合にのみ真になります。

3) バイト *= 2 は 1 ビット左シフトです。私は byte <<= 1 を使用していたでしょう。より明白なようです。

mask /= 256 は 8 ビットの右シフトです。マスクを使用します >>= 8. 同上

除算と倍数は、2 のべき乗を使用する場合、シフト演算子として使用できます。シフト演算子を使用する方が明らかだと思います。

正しい順序で値を取得するには、順序が重要です。

于 2013-02-16T14:33:51.990 に答える
0

2 の累乗で乗算または除算することにより、任意のバイナリ値をシフトできます。これがバイナリ演算のしくみです。

于 2013-02-16T14:24:06.197 に答える
0

あなたの難しさは、ビット単位の操作が算術演算にどのように関係しているかを理解することです。

  • まず、2 を掛けることは、バイナリを 1 ステップ左にシフトすることと同じです。
  • 第二に、これを数回行うと、数ステップ左にシフトします。
  • 3 番目に、2 で割ると、1 ステップ右にシフトします。

これらすべての操作のより良い表記法は、「実際の」シフト演算子を使用することです。

(value & mask) / (256*256*256)

次のように書くほうがよい

(value & mask) >> (3*8)

それは役に立ちますか?

以前は、「DIV」と「MOD」を使用して数値を 2 つの部分に分割することを考えるのが好きでした。ここでN DIV 256、剰余を破棄する整数除算です。したがって、これは実質的に 8 ビットだけ右にシフトし、最下位バイトを破棄します。反対はN MOD 256で、余りを取るだけです。これは実質的ANDに 255 であり、最下位バイトのみが残ります。DIVと結果から、MOD元の数を再構築できます。

LO = X & 255;   // equivalent to (byte)X if X is unsigned
HI = X >> 8 ;   // equivalent to (X / 256) in this case
original = LO | (HI << 8) 
 // equivalent to LO + (HI * 256), in this case
于 2013-02-16T14:26:51.443 に答える
0

mask最初のバイトのビットを除いて、オンに切り替えられたすべてのビットをオフにします。

  0110 0000 0000 0000 0000 0000 0000 0110 0000
& 1111 1111 0000 0000 0000 0000 0000 0000 0000   
= 0110 0000 0000 0000 0000 0000 0000 0000 0000  

なぜなら1 & 0 or 0 & 1 or 0 & 0 == 0 and 1 & 1 == 0

2 で割るとすべてのビットが右にシフトし、2 で乗算するとすべてが左にシフトします。

0x80 == 1000 0000したがって&、この値を使用すると、最初のビットを除くすべてがオフになります。

最初のビットが設定されている場合、結果の値は > 0 であるためブール値の true 値に対応し、そうでない場合はゼロで false に対応します。

于 2013-02-16T14:29:11.847 に答える