Требуется ли объединение выравнивания для заголовка выделения памяти? - PullRequest
3 голосов
/ 15 декабря 2009

В K & R2 они реализуют распределитель памяти в главе 8. Для каждого блока есть заголовок, определенный примерно так (из памяти, код может быть неточным):

union header_t
{
  struct 
  {
     unsigned size;
     unsigned* next; 
  };

  long align;
};

Они делают это, чтобы «убедиться, что заголовок правильно выровнен по границам long». Но разве профсоюз не выравнивается по крупнейшему члену? Структура больше, чем один элемент выравнивания, поэтому заголовок в любом случае будет выровнен по кратным числам структуры, не так ли?

Как насчет того, когда структура еще больше (скажем, в ней много членов). Всегда ли требуется этот прием объединения выравнивания при записи распределителя памяти?

Ответы [ 3 ]

5 голосов
/ 15 декабря 2009

Тип данных в K & R:

union header
{
  struct 
  {
     union header *ptr; 
     unsigned size;
  } s;

  Align x;
};

Допустим, у нас было это вместо:

union header_t
{
  struct 
  {
     union header_t *next; 
     unsigned size;
  } s;
};

(Кстати, вам нужно имя для переменной struct, а также изменить указатель внутри struct для ввода union header_t *, потому что структура данных представляет собой связанный список.)

Реализация

K & R malloc() резервирует часть пространства, а затем использует это для поддержания свободного магазина. Когда это malloc называется, оно находит в свободном списке место, которое имеет достаточно места, и возвращает указатель на этот хвостовой конец.

В частности, соответствующая часть кода:

typedef union header Header;
static Header base;
Header *p = &base;
...
p += p->s.size;
return (void *)(p+1);

Обратите внимание, что мы возвращаем p+1 (приведение к void *), поэтому мы должны убедиться, что этот указатель выровнен для любого типа данных . Поскольку p сам указывает на Header *, мы должны убедиться, что когда мы добавляем sizeof(Header) к выровненному указателю, мы получим еще один выровненный указатель назад (помните, p+1 указывает на sizeof(Header) байт из p). Это требование означает, что Header имеет для выравнивания для всех типов данных.

struct внутри Header может быть не выровнено для максимально широкого типа . Чтобы убедиться, что наш тип Header выровнен так, мы добавляем элемент к union, который, как мы знаем, максимально выровнен, то есть самый широкий тип на данной машине. K & R предполагает, что этот тип long. Также обратите внимание, что не имеет значения, больше ли размер Header, чем размер типа Align. Здесь предполагается, что тип Align здесь - это тип с строжайшими требованиями к выравниванию, а не то, что он будет огромным.

Интересно, что нам нужно предположить тип «максимально выровненный», потому что стандарт C требует выравнивания для любого типа по указателям, возвращаемым malloc, но не указывает переносимый способ выяснить, что это за выравнивание будет. Если стандарт действительно определяет такой тип, можно было бы использовать этот тип вместо long для Align.

1 голос
/ 15 декабря 2009

"Структура больше, чем один элемент выравнивания".

Во-первых, кто говорит? Что если в вашей реализации unsigned и unsigned* - это 32 бита, а long - 128 бит (или, более реалистично, 16 бит и 64 бита)?

Во-вторых, и что? Даже если структура, по крайней мере, такая же большая, как long, это не значит, что она должна иметь как минимум такое же большое выравнивание, как long. Если unsigned и unsigned* не имеют требований к выравниванию, то структура не имеет требований по выравниванию. Но, возможно, long делает.

0 голосов
/ 15 декабря 2009

Размер этих типов данных зависит от платформы. Я предполагаю, что два беззнаковых члена структуры имеют 16 бит, а длинное выравнивание составляет 32 бита или два 32-битных члена в структуре и 64 бита для длинной.

Границы выравнивания будут 32 или 64 бита

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...