2017-10-02 7 views
1

私はCと連携しており、32ビット符号なし整数のビットを変更する方法を理解しようとしています。私はバイナリで符号なし整数のバイトグループを手動で変更する

int a = 17212403u; 

を持っている場合、例えば

は、それが1000001101010001111110011なります。さて、私はこれらのビットを、リトルエンディアン形式で配置されていると仮定すると、最大のビットは1を表し、2番目のビットは2番目のビットを表し、以下同様に、ビットのグループを手動で変更できますか?

たとえば、11番目のビットから15番目のビットに10進値17が入るようにビットを変更したいとします。これはどのように可能ですか?

私は、次のようなことで、その範囲を得ることを考えていた:

unsigned int range = (a << (sizeof(a) * 8) - 14) >> (28) 

しかし、私は今から上に行くためにどこか分かりません。

+1

'int a = 17212403u;'は_unsigned_値を_signed_変数に割り当てています。確かにシフトを実行することは、符号なしの変数と定数を使うことで問題が少なくなります。 'unsigned a = 17212403u; ' – chux

+1

17は10001Bです。ビット11-15も5ビットなのでフィットします。まず、NOT(11111B << 11)のマスクでANDをとることによって、これらのビットを強制的にローにします。その後、17を11箇所上にシフトして、それをORします。 –

+4

リトルビッグエンディアンとビッグエンディアンは、ビット「オーダー」には適用されません。ビットは個々にアドレス可能ではないので、アピールするためのより低いアドレスの概念はない。しかし、リトルエンディアン*バイト*の順序は、「最も左の」バイト(最下位のアドレスを持つバイト)が低位のエンドであることを意味します。これは、「リトルエンディアン」が意味するものとは逆の意味です。 – rici

答えて

2

(1)ビット11..15と(2)をクリアしてから、設定する値に従ってビットを設定する必要があります。 (1)を達成するには、クリアするビットを除いて、すべてのビットが1に設定された「マスク」を作成します。 a & bitMaskを使用してビットを0に設定します。次に、| myValueを使用して、ビットを希望の値に設定します。 は右の位置にマスクと値を配置するためにビットシフト演算子<<を使用します。

int main(int argc, char** argv) { 

    // Let's assume a range of 5 bits 
    unsigned int bitRange = 0x1Fu; // is ...00000000011111 

    // Let's assume to position the range from bit 11 onwards (i.e. move 10 left): 
    bitRange = bitRange << 10;    // something like 000000111110000000000 
    unsigned int bitMask = ~bitRange;  // something like 111111000001111111111 
    unsigned int valueToSet = (17u << 10); // corresponds to 000000101110000000000 

    unsigned int a = (17212403u & bitMask) | valueToSet; 

    return 0; 
} 

これは何が起こっているのかを説明するためのロングバージョンです。簡単に言えば、次のように書くこともできます。

unsigned int a = (17212403u & ~(0x1Fu << 10)) | (17u << 10) 
2

11番目から15番目のビットは5ビットですが、15番目のビットを含めることを前提としています。 5ビットが進値である:0x1f

は、その後、あなたが左にこれらの5ビット11の位置をずらす:0x1f << 11

今、私たちは、私たちは元の変数にクリアしたい11〜15ビットのマスクを持っていますこれ - 私たちは、マスク、ビット単位の反転マスクを変数を反転させていることを行う:a & ~(0x1f << 11)

次に第11ビットまでの値が17をシフトさ:17 << 11

その後、我々は5ビットにビットごとのORその私たちはクリアしました:

unsigned int b = (a & ~(0x1f << 11)) | (17 << 11) 
+2

'0x1fu、17u'のような符号なし定数を使用することをお勧めします – chux

0

ビットフィールドの使用を検討してください。これにより、整数のサブセクションに名前を付けてアクセスし、構造体の整数メンバーであるかのようにアクセスすることができます。 Cビットフィールド上の情報については

は、以下を参照してください。以下は、ビットフィールドを使用して、あなたがやりたいようにコードが https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm

です。構造体の "middle5"メンバはビット11-15を保持します。 "lower11"メンバは、下位11ビットのフィラーであるため、 "middle5"メンバは適切な場所に配置されます。プログラムの

#include <stdio.h> 

void showBits(unsigned int w) 
{ 
    unsigned int bit = 1<<31; 
    while (bit > 0) 
    { 
    printf("%d", ((bit & w) != 0)? 1 : 0); 
    bit >>= 1; 
    } 
    printf("\n"); 
} 

int main(int argc, char* argv[]) 
{ 
    struct aBitfield { 
     unsigned int lower11: 11; 
     unsigned int middle5: 5; 
     unsigned int upper16: 16; 
    }; 

    union uintBits { 
    unsigned int  whole; 
    struct aBitfield parts; 
    }; 

    union uintBits b; 

    b.whole = 17212403u; 

    printf("Before:\n"); 
    showBits(b.whole); 

    b.parts.middle5 = 17; 

    printf("After:\n"); 
    showBits(b.whole);  
} 

出力:もちろん

Before: 
00000001000001101010001111110011 
After: 
00000001000001101000101111110011 

、あなたは様々な分野のために、より意味のあるネーミングを使用したいと思います。

ビットフィールドは異なるプラットフォームで実装される場合があるので注意してください。完全に移植可能でない可能性があります。

関連する問題