内存对齐公式

Zos*_*oso 5 c bit-manipulation

在浏览一些内核代码时,我发现了一个内存对齐公式:

对齐 = ((操作数 + (对齐 - 1)) & ~(对齐 - 1))

所以我什至为此编写了一个程序:

#include <stdio.h>

int main(int argc, char** argv) {
    long long operand;
    long long alignment;
    if(argv[1]) {
        operand = atol(argv[1]);
    } else {
        printf("Enter value to be aligned!\n");
        return -1;
    }
    if(argv[2]) {
        alignment = strtol(argv[2],NULL,16);
    } else {
        printf("\nDefaulting to 1MB alignment\n");
        alignment = 0x100000;
    }
    long long aligned = ((operand + (alignment - 1)) & ~(alignment - 1));
    printf("Aligned memory is: 0x%.8llx [Hex] <--> %lld\n",aligned,aligned);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但我根本不明白这个逻辑。这是如何运作的?

And*_*kyy 12

基本上,该公式将一个整数operand(地址)增加到与 对齐的下一个地址alignment

表达方式

aligned = ((operand + (alignment - 1)) & ~(alignment - 1))
Run Code Online (Sandbox Code Playgroud)

基本上与更容易理解的公式相同:

aligned = int((operand + (alignment - 1)) / alignment) * alignment
Run Code Online (Sandbox Code Playgroud)

例如,操作数(地址)为 102,对齐方式为 10,我们得到:

aligned = int((102 + 9) / 10) * 10
aligned = int(111 / 10) * 10
aligned = 11 * 10
aligned = 110
Run Code Online (Sandbox Code Playgroud)

首先我们添加到地址9并得到111。然后,由于我们的对齐方式是 10,所以基本上我们将最后一位数字清零,即111 / 10 * 10 = 110

请注意,对于 10 的每个幂对齐(即 10、100、1000 等),我们基本上将最后一位数字清零。

在大多数CPU上,除法和乘法运算比按位运算花费更多的时间,所以让我们回到原来的公式:

aligned = ((operand + (alignment - 1)) & ~(alignment - 1))
Run Code Online (Sandbox Code Playgroud)

仅当对齐方式为 2 的幂时,公式的第二部分才有意义。例如:

... & ~(2 - 1) will zero last bit of address.
... & ~(64 - 1) will zero last 5 bits of address.
etc
Run Code Online (Sandbox Code Playgroud)

就像将 10 次方对齐的地址的最后几位清零一样,我们将 2 次方对齐的最后几位清零。

希望它现在对你有意义。