5

以下はmalloc()の非常に単純なバージョンであり、いくらかのスペースを割り当てているように見えますが、free() がなく、割り当てられたスペースをオーバーランしたかどうかを確認しないという事実を除けば、どうすればよいでしょうかコードが正しいことを確認しますか?

「C」の専門家が私を平手打ちする明らかな失敗はありますか?

#include <stdio.h>
#include <unistd.h>

#define MAX_MEMORY 1024 * 1024 * 2 /* 2MB of memory */

void *stack = NULL; /* pointer to available stack */
void * memoryAlloc(size) {
    if (stack == NULL)
        stack = sbrk(MAX_MEMORY); /* give us system memory */

    void *pointer;
    pointer = (void *)stack + size; /* we always have space :) */
    stack += size; /* move in stack forward as space allocated */
    return pointer;
}
4

3 に答える 3

11

Ned Batchelderが指摘した基本的な問題に加えて、はるかに微妙な問題は、割り当てられているオブジェクトに適切に配置されたアドレスをアロケータが返さなければならないことです。一部のプラットフォーム(x86)では、パフォーマンスの問題を除いてこれは問題にならない場合がありますが、多くのプラットフォームでは、これは完全な取引ブレーカーです。

また、ポインター演算を実行するために(char*)キャストを実行する必要がありましたstack(型に対してポインター演算を実行することはできませんvoid*)。

MAX_MEMORYそして、マクロ内の式の周りに親を配置する必要があります。乗算よりも優先順位の高い演算子はすべて正しい構文ではないため、これらがないと優先順位の問題が発生することはないと思います。マクロを使用すると、後悔するよりも常に安全です。(演算子が式全体ではなく、に[]のみバインドできる例外が少なくとも1つありますが、構文的に有効であっても、表示するのは非常に奇妙な状況になります)。2MAX_MEMORYMAX_MEMORY[arrayname]

実際のところ、私はそれを列挙型にしたでしょう。

システム上の基本的なデータ型に合わせて適切に配置されたメモリブロックを返すことで、アロケータを単純に保つことができます(おそらく8バイトの配置)。

/* Note: the following is untested                   */
/*       it includes changes suggested by Batchelder */

#include <stdio.h>
#include <unistd.h>

enum {
    kMaxMemory = 1024 * 1024 * 2, /* 2MB of memory */
    kAlignment = 8
};

void *stack = NULL; /* pointer to available stack */
void * memoryAlloc( size_t size) {
    void *pointer;

    size = (size + kAlignment - 1) & ~(kAlignment - 1);   /* round size up so allocations stay aligned */

    if (stack == NULL)
    stack = sbrk(kMaxMemory); /* give us system memory */

    pointer = stack; /* we always have space :) */
    stack = (char*) stack + size;   /* move in stack forward as space allocated */
    return pointer;
}
于 2009-10-31T18:31:28.737 に答える
6

いくつかの問題があります:

  1. 関数の途中で宣言pointerしますが、これは C では許可されていません。

  2. ポインターをstack+sizeに設定しますが、それを単に にしたいとしますstack。それ以外の場合は、割り当てているメモリ ブロックの末尾へのポインターを返します。その結果、呼び出し元がsizeそのポインターですべてのバイトを使用すると、別のメモリ ブロックとオーバーラップすることになります。異なる時間に異なるサイズのブロックを取得すると、2 つの呼び出し元が同じバイトのメモリを使用しようとすることになります。

  3. を行うと、バイト単位ではなくvoid* 単位でstack += sizeインクリメントされます。これはほとんどの場合、より大きくなります。stacksizesize

于 2009-10-31T18:21:02.470 に答える
2

まず、他の人がすでに指摘しているように、ブロックの途中で変数を宣言しています。これは C99 でのみ許可されていますが、C89/90 では許可されていません。つまり、C99 を使用していると結論付けなければなりません。

次に、関数を K&R スタイル (パラメーターの型なし) で定義していますが、同時にパラメーターの型を後で宣言していません。そうすれば、C99 で非合法化されている「implicit int」ルールに依存することになります。つまり、 C99 を使用していないと結論付けなければなりません。これはすでに「最初に」の部分と矛盾しています。(さらに、 「オブジェクト サイズ」の概念を表すために符号なし型を使用するのが通例です。size_t通常、その目的に使用される専用の型です)。

第 3 に、ポインタに対してポインタ演算を使用していますがvoid *、これは C89/90 と C99 の両方で常に不正です。そこから何を結論できるかさえわかりません:)

使用しようとしている言語を決めてください。そこから始めます。

于 2009-10-31T18:33:57.903 に答える