9

私は少し立ち往生しているという問題を抱えており、同僚から、ここは助けを求めるのに良い場所であると知らされました。

JavaでCスタイルのビットフィールドを実装しようとしています。これは大まかな例です(現時点では、実際のコードは目の前にありません)。

typedef union
{
  typedef struct
  {
     unsigned short a :1;
     unsigned short b :1;
     unsigned short c :2;
     unsigned short d :10;
  } bitfield;

  unsigned short bitmap;
}example_bitfield;

レガシーコードの似たようなスタイルのビットフィールドがたくさんあります。Javaと同等の方法を考え出す必要があるのは、Javaを使用してUDPを使用して他のレガシーアプリケーションと通信するコードに取り組んでいるためです。

コードを書き直すオプションがありません。このアプローチは移植性がなく、エンディアンの問題(およびパディング/アライメントなど)があり、コードを書き直すことができれば、より良い方法で実行できる可能性があることを認識しています。残念ながら、この非常に具体的な問題に対する答えが必要です。システムは閉じているので、コンパイラ/オペレーティングシステム/電気ショック療法のすべての可能な組み合わせについて心配する必要はありません。

Java EnumSetを使用するアプローチは、各値を1ビットにすることしかできないと私は信じているため機能しません。たとえば、dの値が10ビットを占める値をパックできる必要があります。

Javaビットセットについては知っていますが、制限があります。私は古いバージョンのJavaを使用しているので、新しいJavaビットセットメソッド(つまり、おそらく確実に役立つvalueOfメソッド)をいくつか持っていません。

これを可能な限り管理しやすくする方法について誰かが何か考えを持っていますか?通信用に実装する必要のあるビットフィールドが10個以上あります。

あなたが提供できるどんな助けにも感謝します!

4

4 に答える 4

7

UDPはバイト配列のみを受け入れるため、Javaクラスは任意の適切な方法で宣言でき、唯一の重要なステップは、そのシリアル化および逆シリアル化メソッドを定義することです。

class example_bitfield {
  byte a;
  byte b;
  byte c;
  short d;

  public void fromArray(byte[] m) {
    byte b0=m[0];
    byte b1=m[1];
    a=b0>>>7;
    b=(b0>>6)&1;
    c=(b0>>4)&3;
    d=(b0&0xF<<6)|(b1>>>2);
  }
  public void toArray(byte[] m) {
    m[0]=(a<<7)|(b<<6)|(c<<4)|(d>>>6);
    m[1]=(d&0x3F)<<2;
  }
}
于 2012-09-22T18:37:57.153 に答える
5

JavolutionライブラリのClassStructは、必要なものを作成します(http://www.javolution.org/apidocs/index.html?javolution/io/Struct.html)「時計」の例を参照してください。

 import java.nio.ByteBuffer;
 class Clock extends Struct { // Hardware clock mapped to memory.
     Unsigned16 seconds  = new Unsigned16(5); // unsigned short seconds:5
     Unsigned16 minutes  = new Unsigned16(5); // unsigned short minutes:5
     Unsigned16 hours    = new Unsigned16(4); // unsigned short hours:4
     Clock() {
         setByteBuffer(Clock.nativeBuffer(), 0);
     }
     private static native ByteBuffer nativeBuffer();
 }
于 2013-08-21T11:15:00.163 に答える
3

私はここに提示された同様のアプローチを使用することになりました:ビットをパックするためのJavaで最も効率的な方法は何ですか

次に、 LinkedHashMapを使用して個々のビットフィールドエントリを格納するラッパークラスを作成しました。

各フィールドは、ビット数とフィールドの値を格納するクラスとして実装されました。フィールドの名前は、LinkedHashMapのキーです。

構造体を開始および終了するためのメソッド、構造体にビットフィールドを追加するためのメソッド、およびキーに基づいて値を取得および設定するためのメソッドを追加しました。

私のpackメソッドは、LinkedHashMapを反復処理し、ビットオフセットを追跡しながらビットを配置します(この目的で整数を使用しました)。

unpackメソッドは、LinkedHashMapを繰り返してビットを取得し、ビットオフセットを追跡し、値をLinkedHashMapに格納します。

便宜上、ビットフィールドを整数、短整数、長整数、およびバイトにパックするためのメソッドを作成しました。バイト配列と値の間で変換するために、ByteBufferを使用し、wrapメソッドを呼び出しました。

また、最初にByteBufferをデータ型のバイト数(整数の場合は4、shortの場合は2)に割り当て、次にさまざまなputメソッドを呼び出すことによって、パックされた整数、short、long、またはbyteを解凍するメソッドを作成しました。 ByteBuffer。バイト配列を取得したら、それをunpackメソッドに渡すことができました。

このアプローチを採用したのは、自己完結型で、操作が簡単で、他の人が簡単にフォローできるものが必要だったためです...注釈などを含むよりエレガントな方法があることはわかっています(JavaStructを見つけましたがビットフィールドは組み込まれていません。)

さまざまなプリミティブデータ型からのパックおよびアンパックにより、DataInputStream/DataOutputStreamからの結果の読み取りと書き込みが簡単になります。

申し訳ありませんが、すべての人が恩恵を受けるためのコードを投稿することができないため、上記の説明で十分です。うまくいけば、それは同様の状況で誰かを助けるでしょう:)。

于 2012-09-26T02:20:04.740 に答える
1

いくつかの大まかな検索では、これを簡単にするライブラリは見つかりませんでしたが、ビット単位の操作を使用して、いつでも手動でパックおよびアンパックできます。

class ExampleBitfield {
    int bitfield;      // actually 16 bits

    public int getBitfield() {
        return bitfield;
    }
    public void setBitfield(int bitfield) {
        this.bitfield = bitfield & 0xffff;
    }

    // lowest bit
    public int getA() {
        return (bitfield >> 0) & 0x01;
    }
    public int setA(int a) {
        return (bitfield & ~0x01) | ((a & 0x01) << 0);
    }

    // second lowest bit
    public int getB() {
        return (bitfield >> 1) & 0x01;
    }
    public int setB(int b) {
        return (bitfield & ~0x02) | ((b & 0x01) << 1);
    }

    // ...
}
于 2012-09-22T18:20:22.233 に答える