确定运行时参数的性质

时间:2014-01-24 04:18:22

标签: c++ memory new-operator

我有一个功能

void fname(char* Ptr)
{
    ...
}

我想在这个函数内部知道这个指针Ptr是否使用new char[]或者调用函数中本地分配的内存的地址来保存动态分配的内存的地址。有什么方法可以确定吗?我认为<typeinfo>在这里没有帮助。

3 个答案:

答案 0 :(得分:1)

执行此操作的一种方法是拥有自己的operator new函数并跟踪分配的所有内容,以便只要给出的地址是分配的地址,就可以询问您的分配库。然后,自定义分配器只调用标准分配器来实际进行分配。

另一种方法(凌乱和高度依赖OS的细节)可能是检查虚拟内存中的进程布局,从而确定哪些地址引用哪些内存区域。

您可以通过实际管理自己的内存池来结合这些想法。因此,如果您获得具有已知地址范围的单个大块系统内存并将其用于所有new内存,则可以检查地址是否在给定范围内以回答您的问题。

然而:如果这个问题是这样做的唯一目的,那么这些想法中的任何一个都是很多工作而且不合适。

说了这么多,如果你想要实现某些东西,你需要仔细研究可能生成地址的所有方法。

例如(当然我错过了一些):

  • 堆栈
  • 从新
  • 返回
  • 从new。返回的内容。
  • 从新的但已经删除了(希望不是,但这就是我们需要诊断的原因)
  • 静态分配
  • 静态常量记忆
  • 命令行参数/环境
  • 代码地址。

现在,暂时忽略所有这些,并假设这是出于某些调试目的而不是系统设计,您可能会尝试这样的事情:

这是丑陋的,不可靠的,不受标准等保证,但可能有效。 。

char* firstStack  = 0;

bool isOnStack(const void* p)
{
    char* check =(char*)p;
    char * here = (char*)&check;
    int a = firstStack - check;
    int b = check - here;
    return (a*b > 0);
}

void g(const char* p)
{
    bool onStack = isOnStack(p);
    std::cout << p  << (onStack ? "" : " not" ) << " on stack " << std::endl;
}

void f()
{
    char stuff[1024] = "Hello";
    g(stuff);
}

void h()
{
    char* nonsense = new char[1024];
    strcpy(nonsense, "World");
    g(nonsense);
    delete [] nonsense;
}

int main()
{
    int var = 0;
    firstStack = (char*)&var;
    f();
    h();    
}

输出:

  

堆栈上的Hello

     

世界不在堆叠

答案 1 :(得分:0)

答案简短:不,你不能。您无法知道Ptr是否是指向单个char的指针,静态分配的数组的开始,指向单个动态分配的char的指针,或者是否为阵列。

如果你真的想,你会尝试像这样的重载:

template <std::size_t N>
void fname(char Ptr[N])
{
   // ...
}

在传递静态分配的数组时会匹配,而在处理动态分配的内存或指向单个char的指针时会选择第一个版本。

(但请注意,在存在模板的情况下,函数重载规则有点复杂 - 特别是,如果匹配,则首选非模板函数。因此,您可能需要使原始函数采用“虚拟”模板参数如果你采用这种方法。)

答案 2 :(得分:0)

在vc ++中有一个断言_CrtIsMemoryBlock(http://msdn.microsoft.com/en-us/library/ww5t02fa.aspx#BKMK_CRT_assertions),它可以用来检查指针是否是从堆中分配的。这只适用于使用调试堆的情况,但如果您只是想添加一些“仅调试”断言,这样就可以了。在Windows下,这种方法对我来说效果很好。

对于Linux,但我知道没有这样的等价物。

或者,您可以使用内联汇编程序块来尝试确定它是否是堆栈地址。这将取决于硬件,因为它不仅会严重依赖于处理器类型,还会依赖于所使用的内存模型(平面地址模型与分段等)。最好避免这种方法。