2013-11-01 100 views
2

我在读[1]关于堆栈指针和需要知道ebp(函数堆栈的开始)和esp(end)的知识。文章说,你需要知道这两者,因为堆栈可以增长,但我不明白在c/C++中这是如何实现的。 (我不是在谈论另一个函数调用,因为在我看来,这会使堆栈增长,做一些事情,然后递归地弹出并返回到调用状态之前)c/C++在堆栈上分配

我做了一点研究,只看到人说new分配在堆上。但指针将是一个局部变量,对吗?这在编译时是已知的,并在函数被调用时保留在堆栈中。

我开始想,也许与你的循环有局部变量

int a; 
for (int i = 0; i < n; ++i) 
    int b = i + 3; 

不受控制的数量,但没有,这不分配n次b,只有1 INT被保留只是因为它是a

那么...任何例子?

[1):http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames

+0

C和C++中的所有变量都存在于* scope *上下文中。例如,函数中的本地非静态变量仅对该函数自动执行。也就是说,你认为你的代码中'b'的存在范围是什么? – WhozCraig

+0

从编译器的角度来看,在你的例子中没有什么“不受控制的”。 –

+0

文章在哪里说“你需要知道这两者,因为堆栈可以增长”?它只谈谈在栈上传递的参数。 – delnan

回答

5

您可以用STDLIB alloca函数栈上分配内存。我不建议在生产代码中使用此功能。这很容易破坏你的堆栈或堆栈溢出。

+0

C99增加了对也以这种方式分配的变长数组的支持。 'int foo(unsigned sz){char bar [sz]; ...' – nategoose

0

指针确实被分配在栈上。 32位和64位体系结构的大小通常分别为4或8个字节。所以你可以在编译时静态地知道指针的大小,如果你愿意的话,你可以把它们保存在堆栈中。

这个指针指向自由存储,并可以动态分配内存它 - 而无需事先知道大小。此外,保持栈帧空白通常是一个好主意,编译器甚至可以通过(可调整)限制来“强制”这一点。如果我记得正确,MSVC有1MB。

因此,没有,没有办法,你可以创建一个大小的堆栈帧是在编译时未知。您发布的代码的堆栈框架将有3个整数(a,b,i)的空间。 (可能有一些填充,阴影空间等等,不相关。)(技术上可以在运行时扩展堆栈帧的大小,但你几乎不想这样做。)

1

使用EBP更方便。有可能只使用ESP。问题在于,由于函数的参数被压入堆栈,所以所有变量和参数的相对于ESP的地址都会改变。

通过在堆栈上设置EBP为固定,已知的位置,通常为函数的参数和局部变量之间,所有这些元素的地址保持相对于EBP恒定整个功能的寿命。它也可以帮助调试,因为函数结束时ESP的值应等于EBP的值。

我知道在编译时间不确定的增长方式堆栈的唯一方法,就是ALLOCA重复使用。