1

16 ビット アドレスがあり、これをページ番号用に 15-8、オフセット用に 7-0 に分割する必要があります。

それで、私はそれに対してビットごとの操作を行うことができると思いますか?

0xBEEF分割する必要があるアドレスだとしましょう。

ページ番号:
0xBEEF & 0xFF80= 1011 1110 1110 1111 & 1111 1111 1000 0000 = 1011 1110 1000 0000 = 0xBE80

オフセット:
0xBEEF & 0x007F= 1011 1110 1110 1111 & 0000 0000 0111 1111 = 0000 0000 0110 1111 = 0x006F

マクロ用の C のビット演算以外に、これを行う別の方法はありますか?

4

3 に答える 3

4

ほとんどのプログラムでビットシフト演算子を使用できます。

top8 = 0xABCD >> 8; bottom8 = 0xABCD & 0x00FF;

これにより、 と が得られtop8 = 0x00ABますbottom8 = 0x00CD

それらを8ビットシフトする必要はないことに注意してください。それは何でもかまいません。

于 2013-03-10T07:06:36.460 に答える
3

はい、これを別の方法で行う方法がいくつかありますが、どれもお勧めできません。

ビットの順序はハードウェアのエンディアンに依存するため、16 ビット値を上位ビットと下位ビットに分割することは、C では非常に難しい作業です。システムがビッグ エンディアン システムの場合、上位ビットが 2 番目に格納され、システムがリトル エンディアン システムの場合、上位ビットが最初に格納されます。

0xBEEF の例を見てみましょう。メモリ内では次のようになります。

little endian     |     big endian
-------------------------------------
... EF BE ...     |     ... BE EF ...

これらの 2 バイトを分離するためにビット演算を使用している場合、メモリ内の順序を気にする必要はありませんが、事実上他のすべての方法が影響を受けるため、何らかの方法でエンディアンを検出し、移植可能なソリューションを得るために条件付きでプログラムする必要があります。 .

そうは言っても、移植性を気にしない場合に使用できる代替手段がいくつかあります。

1.) キャスト

この方法は、基本的には icepack によって提案された方法です。変数のアドレスを取得し、それを char へのポインターにキャストし、それを配列として扱い、個別のバイトを取得します。

2.) 組合

キャストと同じ効果があるため、次のようなユニオンを作成することもできます。

union myvalue
  {
    uint16_t value;
    uint8_t bytes[2];
  }

バイトと値を別々にアドレス指定できるようにする

3.) 逆

別のまったく異なるアプローチは、最初に16ビットデータを符号なし文字の配列に格納することです。アドレスで計算オーバーヘッドを購入していますが、バイトを分離する必要はありません。もちろん、アドレスがなんらかの計算結果であり、とにかくバイトを分割する必要がある場合、これはもはや意味がありません。

最後の言葉 - コードの移植性を気にする場合は、AND とシフトを使用してバイトを抽出してください。

于 2013-03-10T07:53:59.267 に答える
2

ビット操作なしでこれを行う方法は次のとおりです。

ビッグエンディアン システムの場合:

#define OFFSET(x) (*(unsigned char *)x)
#define PAGE(x)   (*((unsigned char *)x + 1))

リトルエンディアン システムでは、 と の定義を切り替えOFFSETますPAGE

お使いのシステムでは char が 8 ビットであるという前提に注意してください (奇妙な理由がなければ、適切な 8 ビット型を使用してください)。

于 2013-03-10T07:16:22.773 に答える