Я не могу понять приведенный ниже код относительно предоставленного комментария. Что делает этот код, и что будет эквивалентным кодом для 8-aligned
?
/* segment size must be 4-aligned */
attr->options.ssize &= ~3;
Вот, ssize
имеет unsigned int
тип.
Поскольку 4 в двоичном виде равны 100, любое значение, выровненное по 4-байтовым границам (то есть кратное 4), будет иметь последние два бита равными нулю.
3 в двоичном виде — 11, а ~ 3 — побитовое отрицание этих битов, то есть … 1111100. Выполнение побитового И с этим значением сохранит все биты одинаковыми, за исключением двух последних, которые будут очищены (бит & 1 == бит и бит & 0 == 0). Это дает нам следующее меньшее или равное значение, кратное 4.
Чтобы сделать ту же операцию для 8 (1000 в двоичном виде), нам нужно очистить три младших бита. Мы можем сделать это с помощью побитового отрицания двоичного файла 111, то есть ~ 7.
Все степени двух (1, 2, 4, 8, 16, 32 …) могут быть выровнены с помощью простых операций a и.
Это дает размер, округленный в меньшую сторону:
size &= ~(alignment - 1);
или если вы хотите округлить:
size = (size + alignment-1) & ~(alignment-1);
«Alignment-1», если его значение равно степени двух, даст вам «все единицы» до бита только под степенью двойки. ~
инвертирует все биты, поэтому вы получаете единицы для нулей и нули для единиц.
Вы можете проверить, что что-то является степенью двойки:
bool power_of_two = !(alignment & (alignment-1))
Это работает, потому что, например, 4:
4 = 00000100
4-1 = 00000011
& --------
0 = 00000000
или за 16:
16 = 00010000
16-1 = 00001111
& --------
0 = 00000000
Если мы используем 5 вместо:
5 = 00000101
4-1 = 00000100
& --------
4 = 00000100
Так что не сила двух!
Возможно, более понятный комментарий будет
/* make segment size 4-aligned
by zeroing two least significant bits,
effectively rounding down */
Тогда, по крайней мере для меня, мне сразу же задается вопрос: действительно ли оно должно быть округлено, когда это размер? Не будет ли более подходящим округление:
attr->options.ssize = (attr->options.ssize + 3) & ~3;
Как уже говорилось в других ответах, чтобы выровнять их по 8, нужно обнулить 3 бита, поэтому используйте 7
вместо 3
, Итак, мы можем превратить это в функцию:
unsigned size_align(unsigned size, unsigned bit_count_to_zero)
{
unsigned bits = (1 << bit_count_to_zero) - 1;
return (size + bits) & ~bits;
}
~3
это битовый паттерн ...111100
, Когда вы выполняете побитовое И с этим шаблоном, он очищает два нижних бита, то есть округляет до ближайшего кратного 4.
~7
делает то же самое для 8-ми.
Код обеспечивает два нижних бита ssize
очищаются, гарантируя, что ssize
кратен 4. Эквивалентный код для 8-выровнен будет
attr->options.ssize &= ~7;
number = number & ~3
число округляется до ближайший кратный 4 то есть меньший чем number
Пример:
if number is 0,1,2 or 3, the `number` is rounded off to 0
так же if number is 4,5,6,or 7,
числоis rounded off to 4
Но если это связано с выравнивание памяти, память должна быть направлена вверх, а не вниз.