2016-09-22 15 views
0

いくつかのフレーム構造に取り組んでいるうちに、私は奇妙な動作に出くわしました。 は、私はすぐに次のように、独立したサンプルコードでそれをテスト:奇妙な構造体のパッキング

struct non_alligned_struct 
{ 
    uint8_t flag; 

    // start of uint32 bit fields 
    uint32_t a:2; 
    uint32_t b:2; 
    uint32_t c:1; 
    uint32_t d:1; 
    uint32_t e:1; 
    uint32_t f:1; 
    uint32_t g:3; 
    uint32_t h:1; 
    uint32_t i:1; 
    uint32_t j:3; 
    uint32_t k:3; 
    uint32_t l:1; 
    uint32_t m:1; 
    uint32_t n:1; 
    uint32_t o:1; 
    uint32_t p:3; 
    uint32_t q:2; 
    uint32_t r:1; 
    uint32_t s:1; 
    uint32_t t:2; 
    //4 bytes ends here 

    // shouldn't this start at 5th byte ?? 
    uint16_t u; 

    uint16_t v:13; 
    uint16_t w:3; 

    uint16_t x; 

    uint16_t y:13; 
    uint16_t z:3; 
}; 

int main() 
{ 
    struct non_alligned_struct obj1; 
    void *ptr1 = &obj1; 
    void *ptr2 = &(obj1.u); 
    printf("ptr1: %p, ptr2: %p, ptr2 - ptr1: %d\n", ptr1, ptr2, ptr2 - ptr1); 
    return 0; 
} 

出力: PTR1:0x7fff3216a620、PTR2:0x7fff3216a626、PTR2 - PTR1:6

質問:PTR2なぜ - PTR1は6でなければなりません。私の計算によると、5になっているはずです。また、構造体は13バイトなので、4バイトの位置合わせができ、パディングは奇妙な方法で行われます。 Iは、メンバ変数にランダムな値を与えることによって確認し、私は、パディングは、以下太字場所

00000000で行われることを観察:01 22 31 10 67 FE FF 86 01 FE FF 86 01

+0

ptr2-ptr1は6になります... – DigitalNinja

+0

MSVCでは、 'struct'を '#pragma pack(push、1)'と '#pragma pack(pop)'で囲むと、そうでなければ「8」である。 void *型のポインタ算術は実装定義のため、 'void *'ポインタを 'char *'に変更しなければなりませんでした。 –

+0

制約違反が 'void *' sの算術演算をしています。あなたのコンパイラは、このエラーの診断を出す義務がありました。 – EOF

答えて

1

ビットフィールドのアライメントは実装定義です。あなたの実装は、uint32_tフィールドのための1または(おそらく2)バイト整列を使用するように見えます。その結果、flagはバイト0を占有し、ビットフィールドはバイト1..4または2..5を占有する。前者の場合、uは2バイト整列にデフォルト設定され、バイト6.7に設定され、後者の場合、6.7はすでに次の使用可能なスロットです。

+0

OPの太字の16進数ダンプからは、ビットフィールドが1バイトに整列していて、 'u'フィールドが' uint16_t'に期待通りに2バイト整列していると言えます。 – rodrigo

1

質問:なぜPTR2 - それはCが実装は、構造体の任意の量の要素と任意の配置、それらの間と後にパディングを挿入することができます5.

されている必要があります私の計算を1としてPTR1は6でなければなりません選択してください。さらに、ビットフィールドがどのようにアドレス可能な記憶装置に割り振られるか、またそれらが割り当てられるアドレス指定可能な記憶装置がどのようなサイズであるかは規定しない。特に、ビットフィールドの宣言された型は、規格に関しては何も言及していません。最後に

、そのため、あなたはu前に構造体のメンバを表現するために必要とされるビット数を計算することができますが、できないだけ含む構造体の宣言に基づいて行われるべきものをuのオフセットを計算。

実際には、uが構造体の先頭から偶数のオフセットに位置することは驚くことではありません。そのため、構造体の表現にはいくつかのパディングがありますが、パディングがどこにあるかは、ビットフィールドの計算アドレスを取ることができないため、正確に把握するのが困難です。

関連する問題