Если ваша реализация имеет стандартный тип данных, который требует 16-байтового выравнивания (например, long long
), malloc
уже гарантирует, что ваши возвращенные блоки будут выровнены правильно. Раздел 7.20.3 C99 заявляет The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object.
Вы должны передать обратно тот же адрес в free
, который вам дал malloc
. Без исключений. Так что да, вам нужно сохранить оригинал.
См. (1) выше, если у вас уже есть тип, необходимый для выравнивания 16 байтов.
Кроме того, вы можете обнаружить, что ваша реализация malloc
в любом случае дает вам 16-байтовые выровненные адреса для эффективности, хотя это не гарантируется стандартом. Если вам это нужно, вы всегда можете реализовать свой собственный распределитель.
Сам я бы реализовал слой malloc16
поверх malloc
, который использовал бы следующую структуру:
some padding for alignment (0-15 bytes)
size of padding (1 byte)
16-byte-aligned area
Затем вызовите функцию malloc16()
malloc
, чтобы получить блок на 16 байт больше, чем требуется, выясните, где должна быть выровненная область, задайте длину отступа непосредственно перед этим и верните адрес выровненной области.
Для free16
вы просто посмотрите на байт перед указанным адресом, чтобы получить длину заполнения, определите фактический адрес блока malloc'а и передайте его в free
.
Это не проверено, но должно быть хорошее начало:
void *malloc16 (size_t s) {
unsigned char *p;
unsigned char *porig = malloc (s + 0x10); // allocate extra
if (porig == NULL) return NULL; // catch out of memory
p = (porig + 16) & (~0xf); // insert padding
*(p-1) = p - porig; // store padding size
return p;
}
void free16(void *p) {
unsigned char *porig = p; // work out original
porig = porig - *(porig-1); // by subtracting padding
free (porig); // then free that
}
Магическая строка в malloc16
равна p = (porig + 16) & (~0xf);
, которая добавляет 16 к адресу, а затем устанавливает младшие 4 бита в 0, фактически возвращая его к следующей самой низкой точке выравнивания (+16
гарантирует, что оно прошло фактическое начало выделенного блока).
Теперь я не утверждаю, что приведенный выше код является чем-то , но kludgey. Вам нужно было бы протестировать его на интересующих платформах, чтобы убедиться в его работоспособности. Его главное преимущество в том, что он отвлекает отвратительную часть, так что вам никогда не придется об этом беспокоиться.