Распределение памяти в C - PullRequest
       51

Распределение памяти в C

5 голосов
/ 31 октября 2009

ниже приведена очень очень простая версия 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;
}

Ответы [ 3 ]

11 голосов
/ 31 октября 2009

В дополнение к основным проблемам, указанным Недом Батчелдером , гораздо более тонкая проблема заключается в том, что распределитель должен возвращать адрес, который правильно выровнен для любого объекта, который выделяется. На некоторых платформах (x86) это может не иметь значения, за исключением проблем с производительностью, но на многих платформах это полный провал.

Мне также пришлось выполнить (char*) приведение, чтобы выполнить stack арифметику указателя (вы не можете выполнять арифметику указателя на типах void*).

И вы должны ставить скобки вокруг выражения в макросе MAX_MEMORY. Я не думаю, что есть какие-либо проблемы с приоритетом, с которыми вы бы столкнулись без них, так как все операторы с высоким приоритетом, кроме умножения, в любом случае не были бы правильным синтаксисом. С макросами это всегда лучше, чем потом сожалеть. (Существует по крайней мере одно исключение, когда оператор [] может связываться только с 2, а не с целым выражением MAX_MEMORY, но было бы очень странно видеть MAX_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;
}
6 голосов
/ 31 октября 2009

Есть несколько проблем:

  1. Вы объявляете pointer в середине функции, что недопустимо в C.

  2. Вы устанавливаете указатель на stack+size, но вы хотите, чтобы он был просто stack. В противном случае вы возвращаете указатель на конец выделенного блока памяти. В результате, если ваш вызывающий использует все байты size в этом указателе, он будет перекрываться с другим блоком памяти. Если вы получаете блоки разного размера в разное время, у вас будет два абонента, пытающихся использовать одни и те же байты памяти.

  3. Когда вы делаете stack += size, вы увеличиваете stack не на size байт, а на size void *, что почти всегда больше.

2 голосов
/ 31 октября 2009

Во-первых, как уже отмечали другие, вы объявляете переменные в середине блока, что разрешено только в C99, но не в C89 / 90. То есть мы должны сделать вывод, что вы используете C99.

Во-вторых, вы определяете свою функцию в стиле K & R (без типа параметра), но в то же время не объявляете тип параметра позже. Таким образом, вы полагаетесь на правило «implicit int», которое запрещено в C99. То есть мы должны сделать вывод, что вы не используете C99. Это уже противоречие с «первой» частью. (Кроме того, обычно используется беззнаковые типы для представления понятия «размер объекта». size_t - это выделенный тип, обычно используемый для этой цели).

В-третьих, вы используете арифметику указателей для указателя void *, что всегда недопустимо как в C89 / 90, так и в C99. Я даже не знаю, что мы можем из этого сделать:)

Пожалуйста, решите, на каком языке вы пытаетесь использовать, и мы пойдем оттуда.

...