如何查找变量是在堆栈还是堆中分配?
Posted
技术标签:
【中文标题】如何查找变量是在堆栈还是堆中分配?【英文标题】:How to find if a variable is allocated in stack or heap? 【发布时间】:2012-11-23 01:29:39 【问题描述】:在某处偶然发现了这个面试问题,
在 C 中,
给定一个变量x
,如何知道该变量的空间是在栈上还是堆上分配的?
(有没有什么方法可以通过编程方式找到它而不必通过符号表等?找到空间是在堆栈还是堆中分配是否有任何实际意义?)
【问题讨论】:
查看汇编代码..你可以在那里得到它 他还提过什么吗?比如架构、编译器、操作系统?否则我会拒绝。 不,这是唯一给出的信息。 我认为没有便携式解决方案。两种语言都没有堆栈或堆之类的东西,所以问题更多的是关于语言的给定实现。例如,如果您正在查看 GCC,它有大量与 malloc 相关的实用程序可能会有所帮助。 他们通常不是在“正确答案”之后——他们通常是在展示堆、堆栈、调用约定、局部变量所在的位置以及编译器优化等知识之后,方向堆栈增长,不同架构如何管理堆和堆栈等。这是一个相当开放的问题,可以让面试官很好地了解某人知道什么。 【参考方案1】:不,不是一般的。
你知道 gcc -fsplit-stack
吗?
由实现决定是分配一个连续的堆栈还是分配一个堆栈,其中块与内存中的堆块交错。祝你好运,当后者被拆分时,弄清楚是为堆分配了块还是为堆栈分配了块。
【讨论】:
我想对于-fsplit-stack
,您可以合理地回答“两者”作为自动变量。在栈上,栈在堆上。
@SteveJessop:啊!这应该让面试官思考:)
一点用处都没有。我有一个函数destroy_something(something**s)
。知道 *s 是否在堆或堆栈上以了解是否在 *s 上调用 free 将非常有帮助。
@GerardoZinno:这里更简单的解决方案是将销毁和释放分开;如果变量在栈上,释放是自动的,否则所有者必须释放它。
@MatthieuM 是的。我只是说,正如您在编辑之前所说的那样,拥有它并不是一个完全没用的功能:)【参考方案2】:
任何标准都不能保证这一点,但是
在大多数平台上,堆栈从可用的最高地址向下增长,如果地址的最高有效字节位于平台可用内存空间的上半部分,并且您尚未分配,则堆从底部增长千兆字节的内存,这是一个很好的赌注,它在堆栈上。
#include <iostream>
#include <stdlib.h>
int main()
int x = 0;
int* y = new int;
unsigned int a1 = (int) &x;
unsigned int a2 = (int) y;
std::cout<<std::hex<<a1<<" "<<a2<<std::endl;
在我正在输入的机器上输出ffbff474 21600
。
【讨论】:
注意:Prolly 根本不适用于多线程应用程序。【参考方案3】:不,不可能通过内存位置来确定,编译器必须通过 isstack() 支持它才能移植。
【讨论】:
【参考方案4】:这可能是一个棘手的问题。变量具有自动或静态存储持续时间[*]。您可以相当安全地说自动分配是“在堆栈上”,至少假设它们没有优化到寄存器中。存在“堆栈”不是标准的要求,但符合标准的 C 实现必须维护调用堆栈并将自动变量与调用堆栈的级别相关联。所以不管它实际做什么的细节,你几乎可以称之为“堆栈”。
具有静态存储持续时间的变量通常位于一个或多个数据段中。从操作系统的 POV 来看,数据段可能在程序启动之前从堆中分配,但从程序的 POV 来看,它们与“free store”无关。
您可以通过检查源中变量的定义来判断变量的存储持续时间——如果它在函数范围内,那么它是自动的,除非标记为static
。如果它不在函数范围内,那么无论它是否标记为static
,它都具有静态持续时间(因为static
关键字在那里的含义有所不同)。
没有可移植的方法可以根据变量的地址来判断变量的存储持续时间,但特定的实现可能会提供执行此操作的方法,或者您可以使用的工具以或多或少的可靠性进行猜测。
对象也可以具有动态存储持续时间(这通常是“在堆上分配”的意思),但这样的对象不是变量,所以如果有一个。
[*] 或 C11 和 C++11 中的线程本地。
【讨论】:
【参考方案5】:如果您正在研究将堆栈存储在比堆更大的地址上的体系结构,则可以将变量地址与堆栈底部进行比较。使用pthread
线程API,这个比较看起来像这样:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <inttypes.h>
int is_stack(void *ptr)
pthread_t self = pthread_self();
pthread_attr_t attr;
void *stack;
size_t stacksize;
pthread_getattr_np(self, &attr);
pthread_attr_getstack(&attr, &stack, &stacksize);
return ((uintptr_t) ptr >= (uintptr_t) stack
&& (uintptr_t) ptr < (uintptr_t) stack + stacksize);
测试:
int main()
int x;
int *p1 = malloc(sizeof(int));
int *p2 = &x;
printf("%d %d\n", is_stack(p1), is_stack(p2));
return 0;
...按预期打印0 1
。
上面的代码不会从other线程中的堆栈中检测存储。为此,代码需要跟踪所有创建的线程。
【讨论】:
【参考方案6】:我认为它没有解决方案。代码可以通过堆栈(堆)地址范围调整 var 的地址,但这不是一个确切的方式。代码最多只能在某些特定平台上运行。
【讨论】:
以上是关于如何查找变量是在堆栈还是堆中分配?的主要内容,如果未能解决你的问题,请参考以下文章