我可以在 C/C++ 中获得堆栈的限制吗?
Posted
技术标签:
【中文标题】我可以在 C/C++ 中获得堆栈的限制吗?【英文标题】:Can I get the limits of the stack in C / C++? 【发布时间】:2015-04-26 19:24:54 【问题描述】:我的问题非常简单明了:如果我有例如1MB RAM分配给程序的栈,我能得到开始和结束的地址,还是开始和长度的地址?
我正在使用 Visual Studio 2013。
【问题讨论】:
我认为它是特定于操作系统的,所以我帮不了你,但我对答案很感兴趣...... en.wikipedia.org/wiki/Win32_Thread_Information_Block 我猜你对剩下的空闲堆栈没什么兴趣,对吧? 没有便携方法可以做到这一点。 这里有一些很好的答案:***.com/questions/53827/… 【参考方案1】:您应该质疑您对堆栈布局的假设。
也许the stack doesn't have just one top and bottom
也许it has no fixed bottom at all
显然没有可移植的方式来查询不可移植的概念。
不过,在 Visual C++ 中,您可以使用 Win32 API,具体取决于 Windows 版本。
在 Windows 8 上非常简单,只需拨打GetCurrentThreadStackLimits
早期版本需要使用VirtualQueryEx
并对结果进行一些处理。在堆栈中获取一个地址很容易,只需在局部变量上使用&
。然后,您需要找到包含该地址的保留区域的限制。 Joe Duffy 写了a blog post showing the details of finding the bottom address of the stack
【讨论】:
正如Thread Stack Size 所说,default 初始和保留大小可以从 PE 标头中获得(它没有指定 哪个模块的 标头) . @ivan_pozdeev:这只是主线程的堆栈大小,虽然它也用作稍后创建的线程的默认值,但它们的大小是动态设置的。当然,它是可执行映像的 PE 头,与GetModuleHandle(NULL)
匹配的那个。
您认为 Visual C++ == Win32 不会正确的假设 much longer
@Damien_The_Unbeliever:该页面以“Visual C++”的名称快速播放。是的,Visual Studio 开发环境可能针对其他平台,甚至是其他平台上的 C++ 本机开发,但它是通过 Visual C++ 以外的编译器的工具链插件完成的,而不是通过将其他平台添加到 Visual C++ 工具链。使用 Windows Store API 会是一个更好的论据,它不是 Win32,而是使用 Visual C++ 工具链完成的。
@BenVoigt:PE 标头中指定的 默认 堆栈大小不会总是 应用于辅助线程。调用者决定在调用CreateThread()
/_beginthread/ex()
时。【参考方案2】:
GetCurrentThreadStackLimits
似乎在做你正在寻找的事情,将堆栈的下/上边界放入指针地址:
ULONG_PTR lowLimit;
ULONG_PTR highLimit;
GetCurrentThreadStackLimits(&lowLimit, &highLimit);
看起来它只在 Windows 8 和 Server 2012 上可用。
查看MSDN
【讨论】:
【参考方案3】:在 8 之前的 Windows 上,自己实现 GetCurrentThreadStackLimits():
#include <windows.h>
#if _WIN32_WINNT < 0x0602
VOID WINAPI GetCurrentThreadStackLimits(LPVOID *StackLimit, LPVOID *StackBase)
NT_TIB *tib = (NT_TIB *) NtCurrentTeb();
*StackLimit = tib->StackLimit;
*StackBase = tib->StackBase;
#endif
【讨论】:
来自我在回答中链接的 Joe Duffy 文章:不幸的是,StackLimit
仅在您实际触摸堆栈上的页面时才会更新,因此 这不是一种可靠的方式找出还有多少未提交的堆栈。 CLR 使用 kernel32!VirtualAlloc
提交页面,而不是通过实际移动保护页面,因此 StackLimit
不会像您预期的那样更新。 但是如果您阅读下面的 cmets在回答之前的问题,您就已经知道 TIB 不包含所需的信息。
@BenVoigt TIB 确实包含该信息。 GetCurrentThreadStackLimits 返回的“低”值是未记录的 DeallocationStack
字段,位于 FS:[0xE0C]
(x86) / GS:[0x1478]
(x64)。至少从 Windows 2000 开始。因此,可以在 Win8 之前的操作系统上使用未记录的字段,并在 Win8+ 上使用 GetCurrentThreadStackLimits。
@Alex:也许,但这个答案引用了StackLimit
字段,它给出了错误的结果。
@BenVoigt 那么,应该有人编辑答案吗?这是一个有效的答案(考虑到“修复”)——当然比公认的答案建议的更好(通过VirtualQuery
调用内核)。我没有足够的 MS C++ 经验来正确编写它。
@Alex:我仍然坚持我的回答......它在所有平台上都能正常工作,而将未记录的字段从 TIB 中拉出需要每个平台的代码。以上是关于我可以在 C/C++ 中获得堆栈的限制吗?的主要内容,如果未能解决你的问题,请参考以下文章