如何查找变量是在堆栈还是堆中分配?

时间:2012-12-05 09:05:54

标签: c++ c stack heap

在某个地方偶然发现了这个采访问题,

在C中, 给定变量x,您如何确定该变量的空间是否在堆栈或堆上分配?

(有没有办法以编程方式找到它而不必通过符号表等?并且确实找到空间是在堆栈或堆中分配有任何实际意义吗?)

6 个答案:

答案 0 :(得分:12)

不,不是一般。

你知道gcc -fsplit-stack吗?

由实现决定是分配连续堆栈还是堆栈,其中块与内存中的堆块交错。祝你好运,确定在分裂后是否为堆或堆栈分配了一个块。

注意:无论如何,这都是无用的信息......

答案 1 :(得分:9)

如果您正在构建一个将堆栈存储在比堆大的地址上的架构,则可以将变量地址与堆栈的底部进行比较。使用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

上述代码不会检测其他线程中堆栈的存储空间。为此,代码需要跟踪所有创建的线程。

答案 2 :(得分:3)

任何标准BUT都无法保证

在大多数平台上,堆栈从可用的最高地址开始增长,如果地址的最高有效字节位于平台的可用内存空间的上半部分,则堆从底部开始增长,并且您尚未分配千兆字节的内存,这是一个非常好的赌注它在堆栈上。

#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

答案 3 :(得分:2)

这可能是一个棘手的问题。变量具有自动或静态存储持续时间[*]。您可以相当安全地说自动化是“在堆栈上”分配的,至少假设它们没有优化到寄存器中。标准的要求不是存在“堆栈”,但是符合要求的C实现必须维护调用堆栈并将自动变量与调用堆栈的级别相关联。所以无论它实际上做了什么细节,你几乎可以称之为“堆栈”。

具有静态存储持续时间的变量通常存在于一个或多个数据部分中。从操作系统的POV开始,数据部分可能在程序启动之前从堆中分配,但是从程序的POV开始,它们与“免费存储”无关。

您可以通过检查变量在源中的定义来判断变量的存储持续时间 - 如果它在函数范围内,那么除非标记为static,否则它是自动的。如果它不在函数范围内,那么它具有静态持续时间,无论它是否标记为static(因为static关键字意味着不同的东西)。

没有可移植的方法来告诉变量的存储持续时间,但是特定的实现可能会提供方法,或者可以使用更高或更低可靠性的工具来猜测。

对象也可以具有动态存储持续时间(通常是“在堆上分配”意味着什么),但是这样的对象不是变量,所以如果有的话,这将是技巧之一。

[*]或C11和C ++ 11中的线程局部。

答案 4 :(得分:1)

我认为它没有解决方案。代码可以通过堆栈(堆)地址范围来调整var的地址,但这不是一个确切的方法。最多,代码只能在某些特定平台上运行。

答案 5 :(得分:0)

不可能无法确定通过内存位置,编译器必须支持isstack()才能移植。