13

バイナリ形式のパーサーを書いています。このバイナリ形式には、さまざまなフィールドサイズ(通常は50〜100の範囲)を含むバイナリ形式のさまざまなテーブルが含まれます。

これらの構造のほとんどはビットフィールドを持ち、Cで表されると次のようになります。

struct myHeader
{
  unsigned char fieldA : 3
  unsigned char fieldB : 2;
  unsigned char fieldC : 3;
  unsigned short fieldD : 14;
  unsigned char fieldE : 4
}

structモジュールに出くわしましたが、その最低解像度はビットではなくバイトであることに気付きました。それ以外の場合、モジュールはこの作業にほぼ適していました。

ビットフィールドがctypesを使用してサポートされていることは知っていますが、ここでビットフィールドを含むctypes構造体をインターフェースする方法がわかりません。

私の他のオプションは、ビットを自分で操作してバイトにフィードし、構造体モジュールで使用することです-しかし、そのような構造のタイプは50〜100に近いため、そのためのコードを書くとエラーが発生しやすくなります。このツールは大きなギガバイトのバイナリデータを解析するために使用される可能性があるため、効率についても心配しています。

ありがとう。

4

2 に答える 2

7

ビット文字列(あなたが見ていると言っています)を使用すると、実装が簡単になるはずです。まず、デコードするデータを作成します。

>>> myheader = "3, 2, 3, 14, 4"
>>> a = bitstring.pack(myheader, 1, 0, 5, 1000, 2)
>>> a.bin
'00100101000011111010000010'
>>> a.tobytes()
'%\x0f\xa0\x80'

そして、それをもう一度デコードするだけです

>>> a.readlist(myheader)
[1, 0, 5, 1000, 2]

あなたの主な関心事は速度かもしれません。このライブラリは十分に最適化された Python ですが、C ライブラリほど高速ではありません。

于 2011-08-26T10:02:46.250 に答える
6

私はこれを厳密にテストしていませんが、符号なしタイプで動作するようです(編集:符号付きバイト/ショートタイプでも動作します)。

編集2:これは本当にヒットまたはミスです。これは、ライブラリのコンパイラがビットを構造体にパックする方法によって異なりますが、これは標準化されていません。たとえば、gcc 4.5.3では、属性を使用して構造体をパックしない限り機能します。つまり__attribute__ ((__packed__))、6バイトの代わりに4バイトにパックされます。これを確認できます__alignof__sizeof。ctypes構造体定義に追加することでほぼ機能させることが_pack_ = Trueできますが、fieldEでは失敗します。gcc注:「パックされたビットフィールド'fieldE'のオフセットはGCC4.4で変更されました」。

import ctypes

class MyHeader(ctypes.Structure):
    _fields_ = [
        ('fieldA', ctypes.c_ubyte, 3),
        ('fieldB', ctypes.c_ubyte, 2),
        ('fieldC', ctypes.c_ubyte, 3),
        ('fieldD', ctypes.c_ushort, 14),
        ('fieldE', ctypes.c_ubyte, 4),
    ]

lib = ctypes.cdll.LoadLibrary('C/bitfield.dll')

hdr = MyHeader()
lib.set_header(ctypes.byref(hdr))

for x in hdr._fields_:
    print("%s: %d" % (x[0], getattr(hdr, x[0])))

出力:

fieldA: 3
fieldB: 1
fieldC: 5
fieldD: 12345
fieldE: 9

C:

typedef struct _MyHeader {
    unsigned char  fieldA  :  3;
    unsigned char  fieldB  :  2;
    unsigned char  fieldC  :  3;
    unsigned short fieldD  : 14;
    unsigned char  fieldE  :  4;
} MyHeader, *pMyHeader; 

int set_header(pMyHeader hdr) {

    hdr->fieldA = 3;
    hdr->fieldB = 1;
    hdr->fieldC = 5;
    hdr->fieldD = 12345;
    hdr->fieldE = 9;

    return(0);
}
于 2011-08-26T03:22:27.273 に答える