Рассмотрите массив struct foo foos[2]
из двух struct foo
, выровненный с 2 * sizeof (struct foo)
или больше. Обратите внимание, что foos[0]
выровнена с 2 * sizeof (struct foo)
или выше, тогда как foos[1]
выровнена только с sizeof (struct foo)
. Вы можете использовать эту информацию, чтобы узнать, является ли случайный struct foo*
, который указывает на такое выровненное struct foo[2]
, указывает на первый или второй элемент.
Чтобы получить достаточно выровненную память, напишите собственный распределитель или используйте функцию C11 aligned_alloc
. Обратите внимание, что на самом деле не требуется полностью выровнять память, просто чтобы бит, который мы тестировали в other_half
, был очищен.
Наивная реализация функции, чтобы найти другую половину пары struct foo
данной указатель на одну половину выглядит следующим образом:
struct foo *other_half(struct foo *half) {
if ((uintptr_t)half % (2 * sizeof *half) == 0)
return half + 1;
else
return half - 1;
}
Эта функция, однако, не очень эффективна, если sizeof (struct foo)
не сила из двух, поскольку это связано с медленной модульной операцией. Чтобы ускорить процесс, рассмотрите факторизацию sizeof (struct foo)
, которая относится к форме 2 n · q. Легко видеть, что достаточно, чтобы проверить, потому что ((uintptr_t)half & (uintptr_t)1 << n) == 0
2 * sizeof (struct foo)
является кратным 2 N + 1 и, следовательно, имеет биты в позиции 0 до п выключен.
Вычисление п во время компиляции немного сложнее, но, к счастью, нам нужно 1 << n
только, которые могут быть вычислены с немного магии -sizeof (struct foo) & sizeof (struct foo)
:
struct foo *other_half(struct foo *half) {
if ((uintptr_t)half & -sizeof *half & sizeof *half)
return half - 1;
else
return half + 1;
}
Не удалось избежать требования выравнивания путем предоставления 'other_half' с четностью первой структуры? Если задано 'half & -sizeof (* half) & sizeof (* half)', '(half + 1) & -sizeof (* half) & sizeof (* half)' не является и наоборот. Таким образом, они чередуются, и если блок, в котором они находятся, выравнивается, первая структура в блоке будет иметь тот бит, который не установлен. Если в первой структуре блока был установлен бит, вы можете просто перевернуть условное. – hacatu
@hacatu Да, вот почему я говорю: «Обратите внимание, что на самом деле не требуется полностью выровнять память, просто имея бит, который мы тестируем в other_half очищенном, достаточно." – fuz