Уточнение со ссылками, выделяет ли malloc() непрерывную память или нет в каждой системе

#c #malloc #dynamic-memory-allocation

Вопрос:

В книге Kamp;R, глава 8, объясняется, как malloc() создает список блоков в свободной памяти, каждый из которых указывает на следующий (грубо говоря), который не обязательно должен быть непрерывным. С другой стороны, все утверждают, что malloc() распределяет память непрерывным образом, я вижу, что арифметика указателей широко используется, и подобные вопросы есть на этом веб-сайте. Но всегда без какого-либо официального источника.

Я прочитал ссылку на C и не нашел упоминания о смежности, и лучшее, что я нашел, было на справочных страницах Linux и Windows, где они обеспечивают это свойство в своих системах.

Поэтому: предлагает ли malloc() непрерывную память (например, делает арифметику указателей законной) только в канонической современной системе, или это правило регулируется стандартом > C89, который я наивно упустил из виду? Пожалуйста, предоставьте официальную справку. Спасибо.

Ps: это не просто теоретический вопрос. Я пишу некоторый код для старой системы DOS, и мне нужно быть уверенным в правильном использовании malloc.

ПРАВКА: Теперь я понимаю свою ошибку, спасибо. Тем не менее, мне все еще не удается найти официальный ресурс, где четко указано, что один вызов malloc() возвращает непрерывную память (Почему эта информация просто не включена ниже описания функции в стандартной библиотеке…?), Например, здесь нет следов (https://en.cppreference.com/w/c/memory/malloc).

Комментарии:

1. Один malloc вызов возвращает непрерывный блок памяти. Но несколько вызовов malloc не должны возвращать соседние блоки (что и подразумевал Kamp;R).

2. Я не знаю, где это явно указано, но malloc было бы непригодно для использования, если бы это было не так.

3. @user47 Сейчас у меня нет C89 под рукой, но я могу посоветовать вам прочитать главу 5.4 ( Арифметика адресов 5.4 ) книги, в которой четко определено, что такое выделенный блок памяти.

4. @user47 В этом проекте рассмотрим функции управления памятью 7.20.3, утверждения «а затем используется для доступа к такому объекту или массиву таких объектов» и «Возвращаемый указатель указывает на начало (адрес наименьшего байта) выделенного пространства» подразумевают смежные адреса. Доступ к объектам в виде массива объектов в выделенном пространстве был бы невозможен без соседних адресов.

5. @Zilog80 Да, я понимаю! Если вы можете получить доступ к выделенному блоку таким же образом, как и к массиву, у него должны быть смежные адреса. Я полностью согласен, спасибо! Но, честно говоря, я думаю, что они могли бы быть немного более откровенными по этому поводу или, по крайней мере, упомянуть об этом в стандартной библиотеке в описании malloc… 🙂

Ответ №1:

Я думаю, что могу процитировать отрывок, связанный с книгой :

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

Вы неправильно поняли, это говорит о том, что при каждом последующем вызове malloc не обязательно будет все смежное выделенное пространство. Это не означает, что один выделенный блок не является смежным. И, на самом деле, с сегодняшней ОС и современным процессором в игре также есть MMU, я предлагаю вам прочитать об этом.

Комментарии:

1. О, да, да, да, теперь я ясно вижу, в чем была проблема! Я понимал, что каждый блок-это всего лишь один байт памяти, поэтому необходимо прыгать между ними. Скорее всего, каждый блок уже состоит из достаточного количества смежных ячеек, чтобы покрыть запрос пользователя. Затем, когда malloc повторяется, он возвращает другой блок в другом месте. Таким образом, различные блоки разрежены, но каждый из них внутренне смежен и соответствует одному вызову. Спасибо за вашу помощь, я очень благодарен!

Ответ №2:

Цитата означает, что если вы будете вызывать malloc несколько раз, то не обязательно, чтобы выделенные блоки были смежными.

Но при каждом вызове malloc он выделяет один объем памяти соседних байтов. Если он не может этого сделать, он возвращает нулевой указатель.

Из стандарта C (функции управления памятью 7.22.3)

1 Порядок и непрерывность хранения, выделяемых последовательными вызовами функций aligned_alloc, calloc, malloc и realloc, не указаны. Указатель, возвращаемый в случае успешного выделения, соответствующим образом выровнен, чтобы его можно было назначить указателю на объект любого типа с основным требованием выравнивания, а затем использовать для доступа к такому объекту или массиву таких объектов в выделенном пространстве (до тех пор, пока пространство явно не будет освобождено)…

Комментарии:

1. Спасибо за ссылку, моя ошибка! Ваш ответ очень помог, но другой дал мне более четкое представление (поэтому я дал вам 1, но пометил другой зеленой меткой).