我在堆栈上分配了 12 个字符字符串,或者说它是 12 个字节。
使用 gdb(在 Linux 下)反汇编表明,为了在堆栈上为字符串分配空间,esp 移动了 -24(在堆栈下)。
push %ebp
mov %esp,%ebp
sub $0x18,%esp
为什么移动24(0x18)?
最佳答案
如果您的函数调用其他函数,其中一些可能是传出参数的空间;其中一些可能是溢出寄存器的值的临时空间;其中一些可能是填充。这将非常依赖于编译器版本和优化标志。
下面是一些简单的废话代码来说明:
extern int foo(int a, int b);
int bar(int c)
{
char s[12];
s[0] = foo(c, 123);
return 456;
}
这里是在 Debian Lenny 机器上使用 gcc 4.3.2 编译的,没有优化:
bar:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $123, 4(%esp)
movl 8(%ebp), %eax
movl %eax, (%esp)
call foo
movb %al, -12(%ebp)
movl $456, %eax
leave
ret
与您的代码一样,它分配了 24 个字节。以下是它们的用途:
Stack while running bar() : : +-------------------------+ | incoming parameter: c | 8(%ebp) +-------------------------+ --- | return address | 4(%ebp) ^ +-------------------------+ | | old %ebp | (%ebp) | +-------------------------+ | bar()'s stack | s[8]..s[11] | -4(%ebp) | frame: 32 bytes +-------------------------+ | | s[4]..s[7] | -8(%ebp) | +-------------------------+ | | s[0]..s[3] | -12(%ebp) | +-------------------------+ | Stack while running foo() | (unused) | 8(%esp) | : : +-------------------------+ | +-------------------------+ | outgoing parameter: 123 | 4(%esp) | | incoming parameter: b | +-------------------------+ | +-------------------------+ | outgoing parameter: c | (%esp) v | incoming parameter: a | +-------------------------+ --- +-------------------------+ | return address | +-------------------------+ | old %ebp | +-------------------------+ : locals for foo() :
一些实验表明,如果增加s[]
,它会占用未使用的空间;例如如果它是 13 个字节,则堆栈帧大小相同,但 s[]
将提前一个字节开始(在 -13(%ebp)
)- 最多 16字节,其中所有分配的堆栈将实际使用。如果 s
声明为 s[17]
,编译器将分配 40 字节的堆栈而不是 24。
这是因为编译器将堆栈帧的总大小(上图左侧的所有内容,传入参数除外,它实际上位于调用者堆栈帧的底部)四舍五入为16 个字节。 (有关 -mpreferred-stack-boundary
选项,请参阅 gcc 文档。)
关于c - 字符串在栈上的分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4270756/