10

厳密なエイリアシング規則についてかなり読んだ後でさえ、私はまだ混乱しています。私がこれを理解している限り、メモリは割り当てごとに異なる型を格納するために使用される可能性があるため、malloc は解放されたメモリを再利用できないため、これらの規則に従う適切なメモリ アロケータを実装することは不可能です。

明らかに、これは正しくありません。私は何が欠けていますか?厳密なエイリアシングに従うアロケータ (またはメモリ プール) をどのように実装しますか?

ありがとう。

編集:ばかげた簡単な例で私の質問を明確にしましょう:

// s == 0 frees the pool
void *my_custom_allocator(size_t s) {
    static void *pool = malloc(1000);
    static int in_use = FALSE;
    if( in_use || s > 1000 ) return NULL;
    if( s == 0 ) {
        in_use = FALSE;
        return NULL;
    }
    in_use = TRUE;
    return pool;
}

main() {
    int *i = my_custom_allocator(sizeof(int));
    //use int
    my_custom_allocator(0);
    float *f = my_custom_allocator(sizeof(float)); //not allowed...
}
4

4 に答える 4

11

私はあなたが正しいとは思わない。最も厳密なエイリアシングルールでさえ、メモリが実際に目的のために割り当てられた場合にのみカウントされます。割り当てられたブロックがでヒープに解放さfreeれると、それへの参照はないはずであり、によって再び与えることができますmalloc

また、標準ではvoidポインターを他の種類のポインターにキャストできる(そしてまた元に戻す)ことができると明示的に規定されているため、void*によって返されるbyは厳密なエイリアシングルールの対象ではありません。mallocC99セクション7.20.3は次のように述べています。

割り当てが成功した場合に返されるポインタは、任意のタイプのオブジェクトへのポインタに割り当てられ、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用できるように適切に配置されます(スペースが明示的に割り当て解除されるまで) 。


実際にメモリをヒープに戻さない更新(例)に関しては、割り当てられたオブジェクトが特別に扱われるため、混乱が生じると思います。6.5/6C99を参照すると、次のようになります。

保存された値にアクセスするためのオブジェクトの有効なタイプは、オブジェクトの宣言されたタイプです(脚注75:割り当てられたオブジェクトには宣言されたタイプがありません)。

その脚注を読み直してください、それは重要です。

文字型ではない型を持つ左辺値を介して、宣言された型を持たないオブジェクトに値が格納されている場合、左辺値の型は、そのアクセスおよびその後のアクセスを変更しないオブジェクトの有効な型になります。保存された値。

memcpyまたはmemmoveを使用して、宣言された型を持たないオブジェクトに値をコピーする場合、または文字型の配列としてコピーする場合、そのアクセスおよび値を変更しない後続のアクセスの変更されたオブジェクトの有効な型は次のとおりです。値のコピー元のオブジェクトの有効なタイプ(ある場合)。

宣言された型を持たないオブジェクトへの他のすべてのアクセスの場合、オブジェクトの有効な型は、単にアクセスに使用される左辺値の型です。

つまり、割り当てられたブロックの内容は、そこに入力するデータ項目のタイプになります

そこに入れる場合は、 (または互換性のあるタイプ)floatとしてのみアクセスする必要があります。floatを入れる場合は、 (または互換性のあるタイプ)intとしてのみ処理する必要があります。int

すべきでないことの1つは、特定のタイプの変数をそのメモリに入れて、それを別のタイプとして処理しようとすることです。これは、オブジェクトがトラップ表現(未定義の動作を引き起こす)を持つことが許可されているためです。これらの表現は、同じオブジェクトを異なるタイプとして扱うために発生する可能性があります。

したがって、intコード内の割り当て解除の前にそこに格納し、それをfloatポインターとして再割り当てする場合は、実際にそこに配置するまで、floatを使用しないでください。その時点まで、割り当てられたタイプはまだありませんfloat

于 2011-10-07T12:19:33.533 に答える
3

標準 C では、ユーザー作成のメモリ アロケータが、ある型として使用されているメモリ領域を安全に取得し、別の型として安全に利用できるようにするための効率的な手段を定義していません。C の構造体は、表現をトラップしないことが保証されています。これは、不確定値を含むフィールドを持つ構造体を安全にコピーできなければ、ほとんど意味がありません。

難しいのは、次のような構造と機能が与えられることです。

struct someStruct {unsigned char count; unsigned char dat[7]; }
void useStruct(struct someStruct s); // Pass by value

次のように呼び出すことができるはずです:

someStruct *p = malloc(sizeof *p);
p->count = 1;
p->dat[0] = 42;
useStruct(*p);

割り当てられた構造体のすべてのフィールドを最初に書き込む必要はありません。返される割り当てブロックがmallocどのタイプでも使用できることは保証されますが、ユーザーが作成したメモリ管理関数が、バイト単位の方法で (ループまたは memset を使用して) ストレージをクリアしない限り、そのようなストレージの再利用を有効にする方法はありません。 free() と malloc() を使用してストレージをリサイクルします。

于 2017-01-08T22:59:09.770 に答える
0

アロケーター自体の中で、メモリ バッファーを (void *) として参照するだけです。最適化されている場合、厳密なエイリアス最適化はコンパイラによって適用されるべきではありません (そのモジュールはそこに格納されている型を認識していないため)。そのオブジェクトがシステムの残りの部分にリンクされると、十分に放っておく必要があります。

お役に立てれば!

于 2011-10-07T12:22:52.987 に答える