поведение realloc при сокращении памяти, удерживаемой указателем - PullRequest
1 голос
/ 10 ноября 2011

Путаница 1 :
man realloc говорит о том, что объект будет перемещен, если ему потребуется выполнить новое выделение для изменения размера объекта до нового размера.Однако при сокращении есть много мест, где написано , можно перемещать данные в памяти на новое место (SO).Это создает путаницу в моей голове.Как мы находим, что сокращение приведет к новому распределению или нет, поскольку это явно не упомянуто для случая сокращения на страницах руководства и на странице GNU .

Путаница 2 :
Также, когда мы делаем следующее:

void * ptr1 = malloc(SOMEBIGSIZE);
void * ptr2 = realloc(ptr1, SOMESMALLSIZE);

, оценка ptr1==ptr2 результатов верна.Это означает, что ptr2 указывает на то же самое ptr1.Итак, какой из 2.1 или 2.2 является истинным?
(2.1) , чтобы ptr1 не был уменьшен, что может быть плохо, если SOMEBIGSIZE >>> SOMESMALLSIZE и мы не получим никаких преимуществ в плане памяти.
(2.2) если ptr1 сжимается, то что происходит с памятью в диапазоне адресов ptr1 + SOMESMALLSIZE до ptr1 + SOMEHUGESIZE?он освобожден или помечен как свободный?

Ответы [ 5 ]

6 голосов
/ 10 ноября 2011

Стандарт C описывает поведение realloc с точки зрения пользовательской программы. Он не определяет реализацию.

Ниже приведены соответствующие требования (заданные в вашем вопросе), наложенные стандартом на реализации.

C99 Standard 7.20.3.4-1: функция realloc:

Функция realloc освобождает старый объект, на который указывает ptr, и возвращает указатель на новый объект, размер которого указан по размеру. Содержание нового объект должен быть таким же, как у старого объекта до освобождения, до меньшего из новых и старых размеров. Любые байты в новом объекте, превышающие размер старого объекта, имеют неопределенные значения.

C99 Стандарт 7.20.3.4-4:

Функция realloc возвращает указатель на новый объект (который может иметь то же значение, что и указатель на старый объект) , или нулевой указатель, если новый объект не может быть выделен.

2 голосов
/ 10 ноября 2011

Что касается вашей первой путаницы, вам действительно нужно лучше прочитать страницу gnu.

В нескольких реализациях выделения ресурсов для уменьшения размера блока иногда требуется копирование, поэтому он может потерпеть неудачу, если нет другого доступного пространства.

Теперь, для второй путаницы, возможно любое из двух. Это зависит от конкретной реализации malloc, и нет никаких ограничений (насколько я знаю), которые требуют, чтобы один конкретный случай всегда был верным.

0 голосов
/ 11 ноября 2011

Важным уроком здесь является то, что стандарт описывает эффекты из malloc()/realloc(), а не то, что они на самом деле делают .Это сделано для того, чтобы предоставить разработчикам стандартной библиотеки свободу в оптимизации, сокращении или изменении поведения этих функций, не затрагивая код, который их использует. Стандарт не позволяет вам делать предположения о том, что умно или что происходит, потому что это может быть не так.

С точки зрения программиста, это может быть распределителем (за исключением некоторой проверки ошибок)):

  void*
  malloc(size_t amt){
       static char *base = NULL;
       if(base==NULL)
              base = sbrk(0);
       char *c = base+1;
       base=sbrk(amt+5);
       return c;
  }
  void*
  realloc(void *old, size_t amt){
        return memcpy(malloc(amt), old, amt);
  }
  void free(void *v){}

Я называю ее swalloc, Глупый расточитель.

0 голосов
/ 10 ноября 2011

Вот и все.Вы никогда не знаете, когда realloc собирается выделить другой блок памяти и скопировать данные, потому что нет API, который позволял бы вам просматривать внутреннюю часть "malloc" и видеть, может ли выделенная область быть расширена или уменьшена.

0 голосов
/ 10 ноября 2011

Я полагаю, что спецификация не запрещает realloc ничего не делать в этом случае.

Но если ptr1==ptr2 и если функциональность системы malloc не слишком тупая, я мог бы предположить, что он может пометить неиспользуемый диапазон памяти как многократно используемый для будущих malloc -ов, или perhaos иногда возвращает его системе (например, используя munmap системные вызовы в Posix).

И мое (ограниченное) понимание стандартов заставляет меня думать, что реализация, которая всегда возвращает нулевой указатель для malloc и ничего не делает для realloc, все еще соблюдает букву (но не дух) стандартов.

...