4

ハードウェアのレジスタに対応する構造体があります。

typedef unsigned int uint32;
typedef union A_u{
    uint32 words[4];
    struct {

        uint32 a : 2;
        uint32 b : 3;
        uint32 unused : 27;

        uint32 c : 2;
        uint32 d : 3;
        uint32 unused0 : 27;

        uint32 unused1 : 1;
        uint32 e : 1;
        uint32 f : 1;
        uint32 g : 1;
        uint32 h : 1;
        uint32 i : 1;
        uint32 unused2 : 26;

        uint32 reserved6 : 32;
       }s;
}A_t;

main()
{

    A_t obj;
    uint32 val = 1;

    memset(&obj, 0, sizeof(A_t));
    //fills data
    read_data(&obj);

    printf("0x%x\n", obj.words[2]);
    printf("obj.s.h = %d\n", obj.s.h);

}

出力は

0x80000000
obj.sh = 1。

3ワード目は0x80000000なのに、obj.shが1と表示されていてよくわかりません。最初のビットフィールドが最上位ビットであるpowerpcでこれを実行しています。

4

1 に答える 1

4

コンパイラは、メモリ位置が構造体や共用体、その他の複雑なデータ構造のメンバーとどのように整列するかについて、好きなことをかなり自由に行うことができます。

ソースの一部が構造体をある方法で認識し、別の部分で構造体を別の方法で認識したため、配置境界の問題が原因である、構造体を使用した不可解な実行時エラーを見てきました。

C は基本的に構造体をテンプレートとして使用してメモリ領域をオーバーレイします。異なるファイルが構造体を異なる方法で参照する場合、コードの 1 つの部分が別の構造体メンバーへのアドレス オフセットを計算しています。

一部のコンパイラは、構造体メンバーのアラインメント境界を指定できるように、パック アクションを指定できるプラグマを提供します。

ハードウェアとの互換性を維持するために、符号なし文字の配列を使用するのが最善の方法のようです。これにより、符号なし文字の配列要素にインデックスを付けてから、ビットごとの演算子で 8 ビットのいずれかを選択できます。次に、さまざまなアクセス関数、クラス、マクロなどで符号なし文字配列をラップして、読み書きする実際のデータを操作できます。符号なし文字配列を使用すると、移植性も向上する傾向があります。

ビット フィールドは、アプリケーションがよりメモリを節約する方法でインジケーターとフラグを維持するためのより多くの方法のように見えますが、アプリケーションの外部のエンティティ (ハードウェアまたはソフトウェア) との通信にはそれほど有用ではありません。また、アプリケーションが実行されているコンパイラとハードウェアによっては、ビット フィールドを使用すると、ビット フィールドがアクセスされ、パックおよびアンパックされるため、実行時間にわずかなペナルティが生じる場合があります。

于 2012-06-20T15:44:05.520 に答える