C 中的函数参数对齐

Function arguments alignment in C

过程中断过程参数对齐中的数组。 有以下代码:

void _func(unsigned long cnt, int* adr, ...){
    char a[1];
    printf("cnt: %p, adr: %p\n", &cnt, &adr);
}

int main(void){
    _func(0, (int*)1, 2, 3, 4, 5);
    return 0;
}

...用

编译

gcc -m32 -O0 main.c

它输出这个:

cnt: 0xff911960, adr: 0xff91193c

这是 36 (0x24) 字节的差异。问题是 为什么 是?不应该是 sizeof(cnt)?

但是如果我删除 char a[1] 或添加 -O2 标志,差异将是 4 个字节(像往常一样)。

是什么导致了这种行为?

PS: 在compiler explorer网站上,偏移量一直是4字节。

&cnt&adr是参数地址。参数是函数的局部变量,它们被初始化为调用者传递的参数值。编译器不需要对用于传递参数的参数使用相同的 space。

当参数在堆栈上传递时,编译器可能会也可能不会为参数重用其堆栈 space。当在处理器寄存器中传递参数并且需要地址时,因为程序获取地址并打印它,然后编译器必须为堆栈上的参数保留 space ,从中复制值寄存器到堆栈 space(与存储指令一样),并使用堆栈地址 space.

编译器在为此space布局栈时,不需要关心cntadr是连续的参数。它可以组织有关它需要的所有堆栈 space 的数据——用于参数、局部变量、return 地址、用于它自己的目的等等——然后只需将堆栈 space 分配给那些东西以任何顺序。所以你不应该期望 cntadr.

的地址之间有任何密切的关系

(对于具有可变参数的函数,编译器需要以某种方式实现可变参数列表功能。这通常涉及在最后一个固定参数之后在内存中连续使用可变参数,这将是 adr 在例如。这不会在 cntadr 之间强加任何关系。)