как malloc понимает выравнивание?

следуя отсюда

pw = (widget *)malloc(sizeof(widget)); 

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

также см. быстрый pImpl от травы, он сказал:

Выравнивание . Любое выравнивание памяти. Любая память, распределенная динамически через new или malloc, гарантированно будет правильно выровнена для объектов любого типа, но буферы, которые не распределены динамически, не имеют такой гарантии

Мне интересно, как malloc знает выравнивание пользовательского типа?

Требования к выравниванию являются рекурсивными: выравнивание любой struct является просто самым большим выравниванием любого из ее членов, и это понимается рекурсивно.

Например, и предполагая, что выравнивание каждого базового типа равно его размеру (это не всегда верно в целом), struct X { int; char; double; } struct X { int; char; double; } struct X { int; char; double; } имеет выравнивание по double , и оно будет дополнено кратным удвоению (например, 4 (int), 1 (char), 3 (padding), 8 (double)). Структура struct Y { int; X; float; } struct Y { int; X; float; } struct Y { int; X; float; } имеет выравнивание X , которое является самым большим и равным выравниванию double , и Y выкладывается: 4 (int), 4 (padding), 16 (X), 4 (float), 4 (padding) ,

(Все номера являются просто примерами и могут отличаться на вашей машине.)

Поэтому, разбивая его на фундаментальные типы, нам нужно только знать несколько фундаментальных выравниваний, и среди них есть известный самый большой. C ++ даже определяет тип maxalign_t (я думаю), выравнивание которого является наибольшим выравниванием.

Все malloc() нужно сделать, чтобы выбрать адрес, который кратен этому значению.

Я думаю, что самая важная часть цитаты Херба Саттера – это часть, которую я выделил жирным шрифтом:

Выравнивание. Любое выравнивание памяти. Любая память, распределенная динамически через new или malloc, гарантированно будет правильно выровнена для объектов любого типа , но буферы, которые не распределены динамически, не имеют такой гарантии

Он не должен знать, какой тип вы имеете в виду, потому что он выравнивается для любого типа. На любой данной системе существует максимальный размер выравнивания, который когда-либо необходим или значим; например, система с четырьмя байтовыми словами, вероятно, будет иметь максимум 4 байта.

Это также разъясняется man-страницей malloc(3) , в которой, в частности, говорится:

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

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

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

1) Выровняйте с наименьшим общим кратным всех выравниваний. например, если ints требует 4 байтового выравнивания, но указатели требуют 8, затем выделяют все для 8-байтового выравнивания. Это заставляет все выровнять.

2) Используйте аргумент размера, чтобы определить правильное выравнивание. Для небольших размеров вы можете вывести тип, например malloc(1) (при условии, что размеры других типов не равны 1) всегда является символом. new C ++ имеет преимущество безопасного типа и поэтому всегда может принимать решения о выравнивании таким образом.

Раньше для выравнивания C ++ 11 было обработано достаточно просто, используя наибольшее выравнивание, где точное значение было неизвестно, и malloc / calloc все еще работают таким образом. Это означает, что распределение malloc правильно выровнено для любого типа.

Неправильное выравнивание может привести к неопределенному поведению в соответствии со стандартом, но я видел, что компиляторы x86 являются щедрыми и только наказывают с более низкой производительностью.

Обратите внимание, что вы также можете настроить выравнивание с помощью параметров или директив компилятора. (например, пакет pragma для VisualStudio).

Но когда дело доходит до размещения нового , тогда C ++ 11 приносит нам новые ключевые слова под названием alignof и alignas. Вот какой код, который показывает эффект, если максимальное выравнивание компилятора больше 1. Первое место размещения ниже ниже автоматически хорошо, но не второе.

 #include  #include  using namespace std; int main() { struct A { char c; }; struct B { int i; char c; }; unsigned char * buffer = (unsigned char *)malloc(1000000); long mp = (long)buffer; // First placment new long alignofA = alignof(A) - 1; cout << "alignment of A: " << std::hex << (alignofA + 1) << endl; cout << "placement address before alignment: " << std::hex << mp << endl; if (mp&alignofA) { mp |= alignofA; ++mp; } cout << "placement address after alignment : " << std::hex < 

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

EDIT: Заменено дорогостоящее модульное вычисление с помощью побитовых операций. Все еще надеясь, что кто-то найдет что-то еще быстрее.

  • Открытие защищенного паролем pdf-файла с iTextSharp
  • Как получить MethodInfo метода интерфейса, внедряя MethodInfo метода classа?
  • C ++: Когда (и как) называются глобальные статические конструкторы C ++?
  • Пакет гибкости HTML - удаление ненужных тегов без удаления содержимого?
  • Условное форматирование DataGridView
  • «Правильный» способ хранения двоичных данных с помощью C ++ / STL
  • Преобразование lptstr в char *
  • Выполняет ли литье в int после std :: floor гарантированный правильный результат?
  • Почему ArrayList не отмечен ?
  • Эффективный бит бит C / C ++
  • C - Ошибка сегментации с помощью strcmp?
  • Давайте будем гением компьютера.