Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何确定指针是否位于PC/Visual C++; 这是针对PC/Visual C++的(虽然任何其他答案都很有启发性):] < /P>_C++_C_Visual C++_Pointers_Low Level - Fatal编程技术网

如何确定指针是否位于PC/Visual C++; 这是针对PC/Visual C++的(虽然任何其他答案都很有启发性):] < /P>

如何确定指针是否位于PC/Visual C++; 这是针对PC/Visual C++的(虽然任何其他答案都很有启发性):] < /P>,c++,c,visual-c++,pointers,low-level,C++,C,Visual C++,Pointers,Low Level,如何判断指针是否来自堆栈中的对象?例如: int g_n = 0; void F() { int *pA = &s_n; ASSERT_IS_POINTER_ON_STACK(pA); int i = 0; int *pB = &i; ASSERT_IS_POINTER_ON_STACK(pB); } 因此,只有第二个断言(pB)应该跳闸。我在考虑使用一些内联汇编来确定它是否在SS段寄存器或类似的东西中。有人知道这有没有内置的函数,或者

如何判断指针是否来自堆栈中的对象?例如:

int g_n = 0;

void F()
{
    int *pA = &s_n;
    ASSERT_IS_POINTER_ON_STACK(pA);
    int i = 0;
    int *pB = &i;
    ASSERT_IS_POINTER_ON_STACK(pB);
}
因此,只有第二个断言(pB)应该跳闸。我在考虑使用一些内联汇编来确定它是否在SS段寄存器或类似的东西中。有人知道这有没有内置的函数,或者一个简单的方法

谢谢!
RC

无论您做什么,它都是非常特定于平台且不可移植的。假设你同意,继续读下去。如果指针指向堆栈中的某个位置,它将位于当前堆栈指针
%esp
和堆栈顶部之间

void* TopOfStack; // someone must populate this in the first stack frame

bool IsOnTheStack(void* p)
{
  int x;

  return (size_t) p < (size_t) TopOfTheStack &&
         (size_t) p > (size_t) &x;
}
获取堆栈顶部的一种方法是在
main()
的开头读入它。然而,这有几个问题: -堆栈的顶部实际上略高一些,因为C运行时在进入
main()
在C++中,在代码>主()/<代码>之前调用全局对象的构造函数。 -如果应用程序是多线程的,则每个线程都有自己的独立堆栈。在这种情况下,需要一个线程局部变量来描述堆栈的基础

获取当前堆栈指针的一种方法是使用内联程序集:

uint32_t GetESP(void)
{
    uint32_t ret;
    asm
    {
        mov esp, ret
    }
    return ret;
}

当心内联和优化!优化器可能会破坏这段代码。

从技术上讲,在可移植C中,您无法知道。参数堆栈是一个硬件细节,在许多但不是所有的编译器中都是如此。一些编译器会在可能的情况下使用寄存器作为参数(例如,fastcall)


如果您是专门在windows NT上工作的,则需要从调用NtCurrentTeb()中获取线程执行块。有这方面的信息,从中可以得到堆栈范围。你检查指针是否在范围内,你应该准备好了。

忽略“为什么”这个问题。。。如果可以控制顶部堆栈帧,一种简单的方法是将全局变量设置为堆栈对象的地址,然后使用一个函数检查目标指针是否位于该地址和它在堆栈上创建的变量地址之间

void* TopOfStack; // someone must populate this in the first stack frame

bool IsOnTheStack(void* p)
{
  int x;

  return (size_t) p < (size_t) TopOfTheStack &&
         (size_t) p > (size_t) &x;
}
void*TopOfStack;//必须有人在第一个堆栈帧中填充此内容
布尔伊森塔克(无效*p)
{
int x;
返回(大小)p<(大小)TopOfTheStack&&
(尺寸)p>(尺寸)和x;
}
当然,这不适用于多个线程,除非您将TopOfTheStack线程设置为本地


编译器进行的堆栈优化也可能会导致问题。

我会再问一个问题-为什么需要知道?这是没有好处的

我认为,如果编译器在指针比较方面做了一些合理的事情,并且堆栈变小,那么这种方法可能会起作用:

static void * markerTop = NULL;

int main()
{
    char topOfStack;
    markerTop = &topOfStack;
    ...
}

bool IsOnStack(void * p)
{
    char bottomOfStack;
    void * markerBottom = &bottomOfStack;
    return (p > markerBottom) && (p < markerTop);
}
static void*markerTop=NULL;
int main()
{
炭黑;
markerTop=&topOfStack;
...
}
bool IsOnStack(void*p)
{
炉底炭;
void*markerBottom=&bottomOfStack;
返回(p>markerBottom)和&(p
是的,我知道这是非常不可移植的,但这是为了让内部应用程序模仿其他硬件的功能来实现这一点。似乎线程执行块可能是前进的路。

< P>我不相信Visual C++或几乎所有运行在现代Windows(或古32位OS/2)平台上的任何东西,因为在这些平台上堆栈动态增长,即,只有当程序试图访问所谓的保护页时,才分配堆栈的新页。在当前分配的堆栈块的顶部,一个4-KB的巧尽心思构建的内存块(无论如何,对于32位Windows)。操作系统截取程序尝试访问此保护页时生成的异常,(1)在当前分配的堆栈顶部上方映射一个正常有效堆栈的新页面,并(2)在新顶部上方创建另一个保护页,以便以后可以根据需要扩展堆栈。操作系统会一直这样做,直到堆栈达到其极限,并且通常会将该极限设置得非常高

如果您的程序试图访问任何属于堆栈未分配部分但位于保护页上方的地址,您的程序将崩溃,因为操作系统无法对此进行解释。您的程序只是尝试访问其地址空间之外的内存,即使指针理论上属于任务的堆栈段


但是,如果您需要一种方法来确定地址是否属于堆栈的分配部分(即“堆栈上的对象”),那么可以参考Joe Duffy的博客。只是不要使用这里描述的StackLimit,使用其他线程中已经描述过的方法获取堆栈的当前顶部,因此您可以对堆栈的已分配部分进行操作,而不是整个堆栈,可能是部分未分配的堆栈,一

我同意一些人的看法,他们说,在一个不断调整堆栈大小的环境中,很难可靠地做到这一点

但对于“为什么”的人来说,有趣的是,我今天想在一个小型嵌入式平台上做这件事。我有一个函数,它获取指向对象的指针,然后在函数返回后保持该指针一段时间(因为它正在处理指针指向的数据)

我不希望函数的调用者传入自动变量的地址,因为我不希望数据在处理过程中被践踏。调用者必须传入静态数据或常量数据的地址,一个漂亮的“ASSERT_IS_ON_STACK()”宏可能是一个有用的提醒

便携式的?一点也不。可怕的糖果机界面?当然

这就是小型嵌入式系统的本质——好的断言会有所帮助。

好的,关于“为什么”:

某些处理器的内存控制器不能执行DMA或将内存映射到堆栈段或从堆栈段映射内存;所以在一个跨平台的世界里,为了确保我不是
#define ASSERT(v)  printf("assert: %d\n", v);  //so it doesn't really quit
int g_n = 0;
void test_indirectly(void* vp) {
    ASSERT(IS_POINTER_TO_STACK(vp));
}
void F() {
    int *pA = &g_n;
    ASSERT(IS_POINTER_TO_STACK(pA));         //0

    int i = 0;
    int j = 0;
    int *pB = &i;
    ASSERT(IS_POINTER_TO_STACK(pB));         //1
    ASSERT(IS_POINTER_TO_STACK(&j));         //1

    int *pC = (int*)malloc(sizeof(int));
    ASSERT(IS_POINTER_TO_STACK(pC));         //0
    free(pC);
    ASSERT(IS_POINTER_TO_STACK(pC));         //0
    pC = new int;
    ASSERT(IS_POINTER_TO_STACK(pC));         //0
    delete pC;

    char* s = "HelloSO";
    char w[6];
    ASSERT(IS_POINTER_TO_STACK("CONSTANT")); //0
    ASSERT(IS_POINTER_TO_STACK(s));          //0
    ASSERT(IS_POINTER_TO_STACK(&w[0]));      //1
    test_indirectly(&s);                     //1

    int* pD; //uninit
    ASSERT(IS_POINTER_TO_STACK(pD));    //runtime error check

}