2016-09-12 1 views
2

バイトを1ビット左に回転したい。私はこのサイトからいくつかの例を見ていて、このコードに遭遇しました。それは動作しますが、私はへのステップバイステップに感謝しますどのようには動作します。Cビットフィールドを回転させる(説明が必要)

unsigned int _rotl(const unsigned int value, int shift) 
{ 
    if ((shift &= sizeof(value)*8 - 1) == 0)   //What does this do? 
     return value; 
    return (value << shift) | (value >> (sizeof(value)*8 - shift)); 
} 

最初の部分は何ですか?そして、最後の部分はそれほど変わっていないので、あなたはかなり多くのビットを消していくでしょうか?例えば

セイ

value= 0x50 //01010000 
shift = 4 

私は

value << shift 

01010000 << 4 => 00000000 

のためにそして>> 値のため があるでしょう(はsizeof(値)* 8 - シフト)

01010000>> (4*8 - 4) => 00000000 

両方のOR操作をすると0になります。私の理解は間違っていますが、誰かが私のような初心者のためにそれを黙らせていただきたいと思います。ありがとう。

+1

から16ビットの最小値は、かもしれません理論的には64ビットであってもよい)、8ビットではない。あなたが無視してはいけないビットを無視しているので、あなたの結果は間違っています。式を書き換えて8ビットの数値を回転させる必要があります。シフト式の乗数はsizeof(値)ではなく、サイズ1になります。最初の式は、回転が0または 'value'のサイズの倍数であるときに、より多くの作業をすることを避けます。また、シフト数が「値」のビット数より大きい場合は、ビット数を法とするようにシフトを設定します。 –

答えて

2

のは、ステップバイステップでそれを見てみましょう:

unsigned int _rotl(const unsigned int value, int shift) 
{ 
    if ((shift &= sizeof(value)*8 - 1) == 0)   //What does this do? 
    return value; 
    return (value << shift) | (value >> (sizeof(value)*8 - shift)); 
} 

最初の行:

if ((shift &= sizeof(value)*8 - 1) == 0)   //What does this do? 

この文は、最適化し、1行にロールバックチェックです。 2つの条件のいずれかが満たされた場合にはTRUEを返し:

  1. シフトがゼロであるshiftによって指定された回転数は効果

持たないであろう(すなわち、いずれかのビットを回転させない)

  • そうでない場合はFALSEを返しますが、希望する結果を得るために必要な最小回転数も計算し、その値をshiftに格納します。つまり、shift = shift % size_of_integer_data_typeを計算します。

    たとえば、32ビット整数の場合、32ビットで回転すると何も起こりません。それを64,96、または32の他の倍数で回転すると、何も実行されません。私たちの回転の効果が何もしなければ、私たちは多くの時間を節約し、ちょうど早く終了します。

    ただし、必要以上に多くの作業を指定する場合もあります。 32ビット整数の場合は、1ビットだけ回転すると33ビット、65ビット、97ビットなどと同じ効果があります。このコードはこの事実を認識しているので、shiftを97 shift=1を再割り当てし、余分な回転を取り除きます。

    sizeof(value)*8 - 1は、valueの表現のビット数より1少ない値を返します。たとえば、sizeof(value)が4(32ビット整数のシステムの場合)と評価される場合は、4*8 - 1 = 31となります。

    &=オペレータは、ビット単位のAND-割り当てとなります。これは、shiftsizeof(value)*8 - 1のビット単位のANDを行い、その結果をshiftに割り当てることを意味します。前述のように、その式の右辺は、valueのビット数から1を引いたものに等しくなります。したがって、これは、順番にshift = shift % size_of_integer_data_typeを計算する効果を有するvalueの表現のサイズよりも大きいshiftの全てのビットをマスキングする効果を有します。

    具体的には、32ビットのケースを再考。前と同様に、sizeof(value)*8-1は31と評価されます。ビット単位で、この値は0000 0000 0000 0000 0000 0000 0001 1111です。その値はshiftとビット単位でANDされます。 shiftの6番目から32番目のビットは0に設定され、1番目から5番目のビットは変更されません。 97回の回転を指定すると、結果は1になります。

    0000 0000 0000 0000 0000 0000 0110 0001 (97) 
    & 0000 0000 0000 0000 0000 0000 0001 1111 (31) 
    ========================================= 
        0000 0000 0000 0000 0000 0000 0000 0001 (1) 
    

    ここで最後に行うことは、Cでは割り当てステートメントの戻り値が割り当てられた値であることを思い出すことです。したがって、新しい値shiftがゼロであれば、すぐに戻ります。それ以外の場合は、処理を続行します。

    2行目:

    return (value << shift) | (value >> (sizeof(value)*8 - shift)); 
    

    Cは、(それだけシフトを左右している)回転演算子を持っていないので、我々は別々に下位ビットと上位ビットを計算する必要があり、かつビットワイズORで結合します。この行は、それぞれの面を別々に計算する単純な問題です。

    声明value << shiftは、上位ビットを計算します。これは、ビットパターンを左にshiftの場所にシフトします。もう1つの文は、ビットパターンを右にsize_of_integer_type - shiftビットだけシフトすることによって下位ビットを計算します。これは、例では分かりやすいものです。

    valueは小数点値65535を持っていることとshiftは、値26が次に開始値があるしていると仮定します。

    0000 0000 0000 0000 1111 1111 1111 1111 (65535) 
    

    左シフトが私たちを与える:

    1111 1100 0000 0000 0000 0000 0000 0000 (65535 << 26) 
    

    右シフトが与えます私たち:

    0000 0000 0000 0000 0000 0011 1111 1111 (65535 >> 6) 
    

    ビットワイズORコムあなたはこのコードを再書き込みと同じ正しい結果を得ることができ

    1111 1100 0000 0000 0000 0000 0000 0000 (65535 << 26) 
    | 0000 0000 0000 0000 0000 0011 1111 1111 (65535 >> 6) 
    ========================================= 
        1111 1100 0000 0000 0000 0011 1111 1111 (65535 rot 26) 
    

    :これらの結果をbines

    問題の値はおそらく32ビットの番号(ある
    unsigned int _rotl(const unsigned int value, int shift) 
    { 
        //Assume 8 bits in a byte 
        unsigned bits_in_integer_type = sizeof(value)*8; 
        shift = shift % bits_in_integer_type; 
    
        if(shift == 0) return value; //rotation does nothing 
    
        unsigned high_bits = value << shift; 
        unsigned low_bits = value >> (bits_in_integer_type - shift); 
    
        return high_bits | low_bits; 
    } 
    
  • +0

    うわー、ありがとう。私はこれを注意深く読んで勉強します。 – tadm123

    1
    unsigned int _rotl(const unsigned int value, int shift) 
    { 
        // If all bits in value are zero, do nothing and return 
        int bitmaskOfAllOnes = sizeof(value)*8 - 1; 
        if ((shift &= bitmaskOfAllOnes) == 0)   //What does this do? 
         return value; 
    
        // Shift value to the left 
        (value << shift) 
        // shifting right to handle the wrap around 
        | (value >> (sizeof(value)*8 - shift)); 
    } 
    
    e.g. using 16-bit ints 
    value = 0x1001 
    shift = 4 
    sizeof(value) => 2 
    //sizeof(value)*8 - 1 => 0xffff 
    sizeof(value)*8 - 1 => 15 Decimal 
    shift &= bitmaskOfAllOnes => 0x1001 (i.e. not zero) 
    value << shift => 0x0010 
    sizeof(value)*8 - shift => 12 
    value >> (sizeof(value)*8 - shift) => 0x001 
    0x0010 | 0x001 => 0x0011 
    
    +0

    私は '8'の代わりに' CHAR_BIT'を使用します。16/24/32ビット(主にDSP)の1つだけではなく、埋め込みフィールドであっても、正しく覚えていれば、TI DSPの40ビットの大きな「char」でも使用できました。または、Posixを確認するには、 'CHAR_BIT'が8である必要があります。 – deamentiaemundi

    +0

    この部分を明瞭にすることはできますか?sizeof(value)* 8-1 => 0xffff、左部分は2 * 8- 1 = 15(10進数)?では、これは0xffff(65535)とどのように等しくなりますか? – tadm123

    +0

    はい、正しいです。それは小数点15です。私は私の答えを更新します –