1

以下で使用した構造体を参照してください。この問題をポータブルな方法で解決したいと考えています。

構造体の絶対アドレスを見つけるために使用したコードは次のとおりです(char*)data - sizeof(struct block);(ここで、data は構造体ブロック内のデータへのアドレスです)。この構造体では機能しませんでした。

最後のアサートが失敗する以下のテスト プログラムを作成しました。

両方の印刷に変更unsigned int free:1;するunsigned int free;と 12 が印刷されるため、sizeof で期待どおりの結果が得られます。

前もって感謝します。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct block {
        size_t          size;
        struct block*   next;
        unsigned int    free:1;
        char            data[];
};

int main(void)
{
        struct block*   avail;
        struct block*   b;

        avail = malloc(sizeof(struct block) + 10);

        printf("%zu \n", sizeof(struct block)); // prints 12

        printf("%zu\n", avail->data - (char*)&avail->size); //prints 9

        b = (struct block*)((char*)avail->data - 9);
        assert(b == avail);

        b = (struct block*)((char*)avail->data - sizeof(struct block));
        assert(b == avail);

        return 0;
}

編集:ここでスタックオーバーフローに関する答えを見つけたようです:

メンバーのアドレスから構造体の開始アドレスを取得する方法

それは私に正しい絶対アドレスを与えます。

4

2 に答える 2

0

のレイアウト (およびサイズ) に関する唯一の保証は、

struct block {
        size_t          size;
        struct block*   next;
        unsigned int    free:1;
        char            data[];
};

メンバーのアドレス(ビットフィールドを含むユニット)がリストの順序で増加していること、メンバーがタイプに合わせて適切に整列されていること、およびの先頭にパディングがないstructことです。適切に変換された構造体は、その最初のメンバーへのポインターを生成します。コンパイラは、アラインメントに必要な量よりも多くのパディングをメンバー間に自由に挿入できます。

ただし、通常、挿入されるパディングは位置合わせに必要なものだけです。また、 と のサイズとアラインメントの要件はsize_tほとんどstruct block*の実装で同じで、32 ビット システムでは 4 バイト、64 ビット システムでは 8 バイトです。のサイズstruct blockは の倍数でk = sizeof(size_t)あり、最初のバイトはメンバーkによって占有され、次のバイトはポインターによって占有されます。sizeknext

その後、幅 1 の符号なしビット フィールドが続きます。このような小さなビット フィールドは、任意のストレージ ユニットに適合するため、実装では任意のサイズのストレージ ユニットを自由に選択できます。自然な選択は

  • 1 バイトは最小単位なので、
  • sizeof(int)バイト、" ''プレーンな'' int オブジェクトは、実行環境のアーキテクチャによって提案された自然なサイズを持つ" ためです。

ここで、ビットフィールドを含むユニットが 1 バイトのサイズを持つように選択された場合、実装 (および私の実装) の場合のように、dataメンバーは通常、その直後に2*k+1バイトのオフセットに配置されます。の整列charは 1 です。ビットフィールドの単位が のサイズになるように選択された場合int、 のオフセットは にdataなる可能性が高く2*k + sizeof(int)、32 ビット システムではおそらく に等しくなりますがsizeof(struct block)、64 ビット システムではそうではありません。

非常に高い確率で実装を実現できます

offsetof(struct block, data) == sizeof(struct block)

CHAR_BIT * sizeof(size_t) - 1の間に適切な幅 ( )の名前のないビットフィールドを挿入することによって、ただし、移植可能で動作が保証されている唯一の方法はfreedata

struct block *b_addr = (struct block*)((char*)(avail->data) - offsetof(struct block, data));

リンクされた質問に対するGreg Hewgillの回答で述べたように。

于 2012-07-02T18:03:54.597 に答える
-1

sizeof(struct block) - sizeof(char*)struct blockフィールドを含まないのサイズを指定する必要がありdataます。したがって、 へのポインターがある場合dataは、構造体の先頭に到達する必要があります。

b = (struct block*)((char*)avail->data - (sizeof(struct block) - sizeof(char*));
assert(b == avail);

しかし、私はそれをテストしていません。

于 2012-07-02T09:54:54.410 に答える