Каковы требования к выравниванию malloc(1)

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

Для чего требуется выравниваниеmalloc(1),malloc(2), и т. д.

Если выравнивание превышает выделенный размер, каково обоснование такого требования?

1 ответ

Определение функции в стандарте C является кратким и не содержит никаких указаний относительно выравнивания. Аннотация стандарта C23, приведенная ниже, по существу аналогична предыдущим изданиям, за исключением изменения номера главы:

7.24.3.6 Функция malloc

Краткое содержание

       #include <stdlib.h>
void *malloc(size_t size);

Описание

Функция выделяет пространство для объекта, размер которого указан и представление которого неопределенно.

Возврат

Функция возвращает либо нулевой указатель, либо указатель на выделенное пространство.

Что касается требования к выравниванию блоков, вплоть до C17 это было указано в начале родительской главы:

7.22.3 Функции управления памятью
[...]
Указатель, возвращаемый в случае успешного выделения, соответствующим образом выровнен, так что его можно присвоить указателю на любой тип объекта с фундаментальным требованием выравнивания, а затем использовать для доступа к такому объекту или массив таких объектов в выделенном пространстве (пока пространство не будет явно освобождено).

Это означало, что это должно быть правильно выровнено для всех фундаментальных типов, таких какint,long,long longи т. д., и несколько неоднозначно относится к доступу к таким объектам в выделенном пространстве .

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

7.24.3 Функции управления памятью
[...]
Указатель, возвращаемый в случае успешного выделения, соответствующим образом выровнен, так что его можно назначить указателю на любой тип объекта с фундаментальным требованием выравнивания и размером, меньшим или равным запрошенному размеру.. Затем его можно использовать для доступа к такому объекту или массиву таких объектов в выделенном пространстве (пока пространство не будет явно освобождено).

Эта поправка приветствуется: начиная с C23, не требуется выравнивания и последовательные вызовыmalloc(1)может возвращать последовательные адреса в упакованном массиве байтов. Сходным образом,malloc(2)больше не требуется выравнивать объекты размером более 2.malloc(3)будет соответствующим образом выровнено для 2-байтовых объектов, таких какshortна большинстве архитектур и т. д.

Это может вызвать проблемы для пакетов, которые используют исходное требование выравнивания для хранения тегов в младших битах указателей объектов, возвращаемыхmalloc(). Размер передан вmallocв таких системах должно быть больше или равно 2 n , где n — количество битов в теге, обычно ограниченное 3 или 4. Лучшее решение — использоватьaligned_malloc()где требование выравнивания может быть указано и проверено.

Обратите также внимание, что требование выравнивания для блока, возвращаемогоcalloc(4, 1)равен 4, поскольку выделенный размер является произведением аргументов, первый из которых — это количество элементов, для которых нужно выделить пространство, а второй — размер элемента. Следовательно, программистам не нужно знать точную семантику аргументов. Обратите внимание, чтоnelemsиsizeпередаются в другом порядке в других функциях библиотеки C, которые принимают такие аргументы, напримерfread(),fwrite(),qsort()иbsearch().

realloc()подчиняется тем же требованиям: уменьшение размера блока может привести к созданию другого указателя с более слабым выравниванием.

Другие вопросы по тегам