了解堆栈分配和对齐

Asi*_*ake 7 c stack memory-management memory-alignment

我试图理解堆栈对齐是如何工作的,如什么是"堆栈对齐"?但我很难得到一个小例子来证明上述行为.我正在检查我的函数foo的堆栈分配:

void foo() {
    int a = 0;
    char b[16];
    b[0] = 'a';
}
Run Code Online (Sandbox Code Playgroud)

我编译了源文件gcc -ggdb example.c -o example.out(即没有任何编译器标志),并且gdb中的汇编器转储读取:

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x20,%esp
0x0804839a <+6>:    movl   $0x0,-0x4(%ebp)
0x080483a1 <+13>:   movb   $0x61,-0x14(%ebp)
0x080483a5 <+17>:   leave  
0x080483a6 <+18>:   ret    
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

我的堆栈以16字节的块分配(我通过其他几个测试验证了这一点).根据汇编程序转储,这里分配了32个字节,因为(16 <4 + 16 <32),但我希望在前16个字节上分配整数'a',然后在接下来的16个字节上分配字符数组(在中间留下12个字节的空间).但似乎整数和字符数组都被分配了一个20字节的连续块,根据我上面提到的讨论,这是低效的.有人可以解释我在这里缺少的东西吗?

编辑:我得出结论,我的堆栈分配16个字节的块,使用如下程序:

void foo() {
    char a[1];
}
Run Code Online (Sandbox Code Playgroud)

和相应的汇编程序转储:

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x10,%esp
0x0804839a <+6>:    leave  
0x0804839b <+7>:    ret    
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

您可以看到已在堆栈上为大小为1的字符数组分配了16个字节(仅需要1个字节).我可以将数组的大小增加到16并且汇编程序转储保持不变,但是当它为17时,它在堆栈上分配32个字节.我运行了很多这样的样本,结果是一样的; 堆栈内存以16字节的块分配.在堆栈分配,填充和对齐中已经讨论过类似的主题,但我更热衷于发现的是为什么对齐在我的示例中没有影响.

Oli*_*rth 6

我认为你错过了这样一个事实,即不需要将所有堆栈变量单独对齐到16字节边界.

  • 这是正确的.16字节堆栈对齐是指堆栈指针值的对齐,而不是任何特定堆栈分配变量的地址. (3认同)