Каковы требования к выравниванию 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()
подчиняется тем же требованиям: уменьшение размера блока может привести к созданию другого указателя с более слабым выравниванием.