可以 C++类判断它是在栈上还是在堆上?

发布于 2024-08-17 15:32:47 字数 471 浏览 5 评论 0原文

我有

class Foo {
....
}

Is there a way for Foo to be able to split out:

function blah() {
  Foo foo; // on the stack
}

并且

function blah() {
  Foo foo* = new Foo(); // on the heap
}

我希望 Foo 能够根据它是在堆栈还是堆上分配来执行不同的操作。

编辑:

很多人问我“为什么这样做?”

答案:

我现在使用的是引用计数 GC。但是,我希望有能力运行 mark & 。扫也。为此,我需要标记一组“根”指针——这些是堆栈上的指针。因此,对于每个类,我想知道它们是在堆栈中还是在堆中。

I have

class Foo {
....
}

Is there a way for Foo to be able to separate out:

function blah() {
  Foo foo; // on the stack
}

and

function blah() {
  Foo foo* = new Foo(); // on the heap
}

I want Foo to be able to do different things depending on whether it's allocated on the Stack or the Heap.

Edit:

Alof of people have asked me "why do this?"

The answer:

I'm using a ref-counted GC right now. However, I want to have ability to run mark & sweep too. For this, I need to tag a set of "root" pointers -- these are the pointers on the stack. Thus, for each class, I'd like to know whether they're in the stack or in the heap.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

南街九尾狐 2024-08-24 15:32:47

一种巧妙的方法是:

struct Detect {
   Detect() {
      int i;
      check(&i);
   }

private:
   void check(int *i) {
      int j;
      if ((i < &j) == ((void*)this < (void*)&j))
         std::cout << "Stack" << std::endl;
      else
         std::cout << "Heap" << std::endl;
   }
};

如果对象是在堆栈上创建的,那么它必须位于外部函数堆栈变量方向的某个位置。堆通常从另一侧增长,因此堆栈和堆会在中间的某个地方相遇。

(肯定有一些系统是行不通的)

A hacky way to do it:

struct Detect {
   Detect() {
      int i;
      check(&i);
   }

private:
   void check(int *i) {
      int j;
      if ((i < &j) == ((void*)this < (void*)&j))
         std::cout << "Stack" << std::endl;
      else
         std::cout << "Heap" << std::endl;
   }
};

If the object was created on the stack it must live somewhere in the direction of the outer functions stack variables. The heap usually grows from the other side, so that stack and heap would meet somewhere in the middle.

(There are for sure systems where this wouldn't work)

自找没趣 2024-08-24 15:32:47

您需要实际问我们真正的问题(a):-)可能很清楚为什么您认为这是必要的,但它几乎可以肯定不是。事实上,这几乎总是一个坏主意。换句话说,您认为您为什么需要这样做?

我通常发现这是因为开发人员希望根据对象的分配位置来删除或不删除对象,但这通常应该留给代码的客户端而不是代码本身。


更新:

既然您已经澄清了问题的原因,我很抱歉,您可能已经发现了您所问的问题有意义的少数几个领域之一(运行您自己的垃圾收集进程) )。理想情况下,您应该重写所有内存分配和取消分配运算符,以跟踪堆中创建和删除的内容。

但是,我不确定拦截类的 new/delete 是否是一个简单的问题,因为可能存在未调用 delete 的情况,并且由于 mark/sweep 依赖于引用计数,因此您需要能够拦截指针分配才能正常工作。

你有没有想过你要如何处理这件事?

经典示例:

myobject *x = new xclass();
x = 0;

不会导致删除调用。

另外,您将如何检测到指向某个实例的指针位于堆栈上这一事实? new 和 delete 的拦截可以让你存储对象本身是基于堆栈还是基于堆,但我不知道如何知道指针将被分配到哪里,特别是使用如下代码:

myobject *x1 = new xclass();  // yes, calls new.
myobject *x2 = x;             // no, it doesn't.

也许你可以想研究一下 C++ 的智能指针,它对于淘汰手动内存管理大有帮助。共享指针本身仍然可能会遇到循环依赖等问题,但明智地使用弱指针可以轻松解决这个问题。

您的场景中可能不再需要手动垃圾收集。


(a) 这称为 X/Y 问题。很多时候,人们会提出一个预先假设一类解决方案的问题,而更好的方法只是描述问题,而不对最佳解决方案是什么有先入之见。

You need to actually ask us the real question(a) :-) It may be apparent to you why you think this is necessary but it almost certainly isn't. In fact, it's almost always a bad idea. In other words, why do you think you need to do this?

I usually find it's because developers want to delete or not delete the object based on where it was allocated but that's something that should usually be left to the client of your code rather than your code itself.


Update:

Now that you've clarified your reasons in the question, I apologise, you've probably found one of the few areas in which what you're asking makes sense (running your own garbage collection processes). Ideally, you'd override all the memory allocation and de-allocation operators to keep track of what is created and removed from the heap.

However, I'm not sure it's a simple matter of intercepting the new/delete for the class since there could be situations where delete is not called and, since mark/sweep relies on a reference count, you need to be able to intercept pointer assignments for it to work correctly.

Have you thought about how you're going to handle that?

The classic example:

myobject *x = new xclass();
x = 0;

will not result in a delete call.

Also, how will you detect the fact that the pointer to one of your instances is on the stack? The interception of new and delete can let you store whether the object itself is stack or heap-based but I'm at a loss as to how you tell where the pointer is going to be assigned to, especially with code like:

myobject *x1 = new xclass();  // yes, calls new.
myobject *x2 = x;             // no, it doesn't.

Perhaps you may want to look into C++'s smart pointers, which go a long way toward making manual memory management obsolete. Shared pointers on their own can still suffer from problems like circular dependencies but the judicious use of weak pointers can readily solve that.

It may be that manual garbage collection is no longer required in your scenario.


(a) This is known as the X/Y problem. Many times, people will ask a question that pre-supposes a class of solution whereas a better approach would be just to describe the problem with no preconceptions of what the best solution will be.

蓬勃野心 2024-08-24 15:32:47

答案是否定的,没有标准/便携式方法可以做到这一点。涉及重载新运算符的黑客行为往往存在漏洞。依赖于检查指针地址的黑客行为是特定于操作系统和堆实现的,并且可能会随着操作系统的未来版本而改变。您可能对此感到满意,但我不会围绕这种行为构建任何类型的系统。

我将开始寻找不同的方法来实现你的目标 - 也许你可以有一个完全不同的类型作为你的方案中的“根”,或者要求用户(正确地)使用特殊的构造函数来注释堆栈分配的类型。

The answer is no, there is no standard/portable way to do this. Hacks involving overloading the new operator tend to have holes. Hacks that depend on checking pointer addresses are OS specific and heap implementation specific, and may change with future versions of the OS. You may be comfortable with that, but I wouldn't build any sort of system around this behavior.

I would start looking at different ways to accomplish your goal - perhaps you can have a totally different type to serve as the "root" in your scheme, or require the users to (properly) annotate the stack allocated types as such with a special constructor.

や三分注定 2024-08-24 15:32:47

如果将“this”的值与堆栈指针的当前值进行比较,这是可能的。如果这< sp 那么你已经在栈中分配了。

试试这个(在 x86-64 中使用 gcc):

#include <iostream>

class A
{
public:
    A()
    {
        int x;

        asm("movq %1, %%rax;"
            "cmpq %%rsp, %%rax;"
            "jbe Heap;"
            "movl $1,%0;"
            "jmp Done;"
            "Heap:"
            "movl $0,%0;"
            "Done:"
            : "=r" (x)
            : "r" (this)
            );

        std::cout << ( x ? " Stack " : " Heap " )  << std::endl; 
    }
};

class B
{
private:
    A a;
};

int main()
{
    A a;
    A *b = new A;
    A c;
    B x;
    B *y = new B;
    return 0;
}

它应该输出:

Stack 
Heap 
Stack 
Stack 
Heap

It is possible if you compare the value of 'this' with the current value of the stack pointer. If this < sp then you have been allocated in the stack.

Try this out (using gcc in x86-64):

#include <iostream>

class A
{
public:
    A()
    {
        int x;

        asm("movq %1, %%rax;"
            "cmpq %%rsp, %%rax;"
            "jbe Heap;"
            "movl $1,%0;"
            "jmp Done;"
            "Heap:"
            "movl $0,%0;"
            "Done:"
            : "=r" (x)
            : "r" (this)
            );

        std::cout << ( x ? " Stack " : " Heap " )  << std::endl; 
    }
};

class B
{
private:
    A a;
};

int main()
{
    A a;
    A *b = new A;
    A c;
    B x;
    B *y = new B;
    return 0;
}

It should output:

Stack 
Heap 
Stack 
Stack 
Heap
窝囊感情。 2024-08-24 15:32:47

一种更直接且侵入性较小的方法是在内存区域映射(例如 /proc//maps)中查找指针。每个线程都有一个分配给其堆栈的区域。静态和全局变量将位于 .bss 部分,常量位于 rodata 或 const 段中,等等。

A more direct, and less intrusive method would be to look up the pointer in the memory region maps (such as /proc/<pid>/maps). Each thread has a region allocated to its stack. Static and global variables will live in the .bss section, constants in a rodata or const segment, and so on.

短叹 2024-08-24 15:32:47

我不确定你在问什么,但覆盖 new 运算符可能就是你想要做的。由于在 C++ 中在堆上创建对象的唯一安全方法是使用 new 运算符,因此您可以区分堆上存在的对象与其他形式的内存。谷歌“在c++中重载新的”以获取更多信息。

但是,您应该考虑是否真的有必要在类内部区分这两种类型的内存。如果你不小心的话,让一个对象根据其存储位置而表现不同,听起来就像是灾难的根源!

I am not positive what you are asking, but overriding the new operator may be what you are trying to do. As the only safe way to create an object on the heap in C++ is to use the new operator, you can differentiate between objects that exist on the heap versus other forms of memory. Google "overloading new in c++" for more information.

You should, however, consider if differentiating between the two types of memory is really necessary from inside the class. Having an object behave differently depending upon where it is stored sounds like a recipe for disaster if you are not careful!

如上所述,您需要通过重载的 new 运算符来控制对象的分配方式。但是要注意两件事,首先是“placement new”运算符,它在用户预先分配的内存缓冲区内初始化对象;其次,没有什么可以阻止用户简单地将任意内存缓冲区转换为对象类型:

char buf[0xff]; (Foo*)buf;

另一种方法是,大多数运行时使用的内存比进行堆分配时要求的内存多一些。他们通常在那里放置一些服务结构,以通过指针识别正确的释放。您可以检查这些模式的运行时实现,尽管这会使您的代码确实难以移植、危险且无法支持的过度杀伤力。

同样,如上所述,当您应该询问您设计此解决方案的初始问题(“为什么”)时,您实际上是在询问解决方案的详细信息(“如何”)。

As mentioned above, you need to control how your object is allocated through overloaded new operator. Watch out for two things however, first the 'placement new' operator that initializes your object inside the memory buffer preallocated by user; second, nothing stops the user from simply casting arbitrary memory buffer into your object type:

char buf[0xff]; (Foo*)buf;

Another way is the fact that most runtimes use a bit more memory than asked when doing heap allocations. They usually place some service structure there to identify proper deallocations by pointer. You could inspect your runtime implementation for these patterns, although it will make your code really unportable, dangerous and unsupportable overkill.

Again, as mentioned above, you really are asking for solution details ("how") when you should ask about the initial problem you devised this solution for ("why").

离线来电— 2024-08-24 15:32:47

pax 提出的元问题是“你为什么要这样做”,你可能会得到更丰富的答案。

现在假设您出于“充分的理由”(也许只是好奇)这样做,可以通过重写运算符 new 和 delete 来获得此行为,但不要忘记重写所有 12 个变体,包括:

new、删除、新建不抛出、删除不抛出、新数组、删除数组、新数组不抛出、删除数组不抛出、放置新、放置删除、放置新数组、放置删除数组。

您可以做的一件事是将其放入基类中并从中派生。

这有点痛苦,那么您想要什么不同的行为呢?

The meta question as asked by pax is asked "why would you want to do that" you'll likely get a more informative answer.

Now assuming you're doing this for "a good reason" (perhaps just curiousity) can get this behaviour by overriding operators new and delete, but don't forget to override all 12 variants including:

new, delete, new no throw, delete no throw, new array, delete array, new array no throw, delete array no throw, placement new, placement delete, placement new array, placement delete array.

One thing you can do is put this in a base class and derive from it.

This is kind of a pain, so what different behavior did you want?

可爱咩 2024-08-24 15:32:47

不,它无法可靠或明智地完成。

您可以通过重载 new 来检测何时为对象分配了 new

但是,如果该对象被构造为类成员,并且所属类在堆上分配怎么办?

这是添加到您已有的两个代码示例中的第三个代码示例:

class blah {
  Foo foo; // on the stack? Heap? Depends on where the 'blah' is allocated.
};

静态/全局对象怎么样?您如何区分它们与堆栈/堆?

您可以查看对象的地址,并使用它来确定它是否在定义堆栈的范围内。但堆栈的大小可能会在运行时调整。

所以,实际上,最好的答案是“C++ 不使用标记和清除 GC 是有原因的”。
如果您想要一个合适的垃圾收集器,请使用另一种支持它的语言。

另一方面,大多数经验丰富的 C++ 程序员发现,当您学习了资源管理的必要技术时,对垃圾收集器的需求几乎消失了(RAII)。

Nope, it can't be done reliably or sensibly.

You may be able to detect when an object is allocated with new by overloading new.

But then what if the object is constructed as a class member, and the owning class is allocated on the heap?

Here's a third code example to add to the two you've got:

class blah {
  Foo foo; // on the stack? Heap? Depends on where the 'blah' is allocated.
};

What about static/global objects? How would you tell them apart from stack/heap ones?

You could look at the address of the object, and use that to determine if it is within the range that defines the stack. But the stack may be resized at runtime.

So really, the best answer is that "there's a reason why mark & sweep GC's aren't used with C++".
If you want a proper garbage collector, use a different language, one which supports it.

On the other hand, most experienced C++ programmers find that the need for a garbage collector pretty much vanishes when you learn the necessary techniques for resource management (RAII).

王权女流氓 2024-08-24 15:32:47

MFC类的一种方式:

.H

class CTestNEW : public CObject
{
public:
    bool m_bHasToBeDeleted;
    __declspec(thread) static void* m_lastAllocated;
public:
#ifdef _DEBUG
    static void* operator new(size_t size, LPCSTR file, int line) { return internalNew(size, file, line); }
    static void operator delete(void* pData, LPCSTR file, int line) { internalDelete(pData, file, line); }
#else
    static void* operator new(size_t size) { return internalNew(size); }
    static void operator delete(void* pData) { internalDelete(pData); }
#endif
public:
    CTestNEW();
public:
#ifdef _DEBUG
    static void* internalNew(size_t size, LPCSTR file, int line)
    {
        CTestNEW* ret = (CTestNEW*)::operator new(size, file, line);
        m_lastAllocated = ret;
        return ret;
    }

    static void internalDelete(void* pData, LPCSTR file, int line)
    {
        ::operator delete(pData, file, line);
    }
#else
    static void* internalNew(size_t size)
    {
        CTestNEW* ret = (CTestNEW*)::operator new(size);
        return ret;
    }

    static void internalDelete(void* pData)
    {
        ::operator delete(pData);
    }
#endif
};

.CPP

#include "stdafx.h"
.
.
.
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

void* CTestNEW::m_lastAllocated = NULL;
CTestNEW::CTestNEW()
{
    m_bHasToBeDeleted = (this == m_lastAllocated);
    m_lastAllocated = NULL;
}

A way for MFC classes:

.H

class CTestNEW : public CObject
{
public:
    bool m_bHasToBeDeleted;
    __declspec(thread) static void* m_lastAllocated;
public:
#ifdef _DEBUG
    static void* operator new(size_t size, LPCSTR file, int line) { return internalNew(size, file, line); }
    static void operator delete(void* pData, LPCSTR file, int line) { internalDelete(pData, file, line); }
#else
    static void* operator new(size_t size) { return internalNew(size); }
    static void operator delete(void* pData) { internalDelete(pData); }
#endif
public:
    CTestNEW();
public:
#ifdef _DEBUG
    static void* internalNew(size_t size, LPCSTR file, int line)
    {
        CTestNEW* ret = (CTestNEW*)::operator new(size, file, line);
        m_lastAllocated = ret;
        return ret;
    }

    static void internalDelete(void* pData, LPCSTR file, int line)
    {
        ::operator delete(pData, file, line);
    }
#else
    static void* internalNew(size_t size)
    {
        CTestNEW* ret = (CTestNEW*)::operator new(size);
        return ret;
    }

    static void internalDelete(void* pData)
    {
        ::operator delete(pData);
    }
#endif
};

.CPP

#include "stdafx.h"
.
.
.
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

void* CTestNEW::m_lastAllocated = NULL;
CTestNEW::CTestNEW()
{
    m_bHasToBeDeleted = (this == m_lastAllocated);
    m_lastAllocated = NULL;
}
眼中杀气 2024-08-24 15:32:47

为你的类重载 new() 。这样您就可以区分堆和堆栈分配,但不能区分堆栈和静态/全局分配。

Overload new() for your class. This way you'll be able to tell between heap and stack allocation, but not between stack and static/global.

回心转意 2024-08-24 15:32:47

我建议改用智能指针。根据设计,类应该具有有关类的数据和信息。簿记任务应委托给课堂外。

重载new和delete可能会导致比你想象的更多的漏洞。

I would recommend using smart pointers instead. By design, the class should have data and information about class. Book-keeping tasks should be delegated outside the class.

overloading new and delete can lead to more holes than you can imagine.

自演自醉 2024-08-24 15:32:47

要回答您的问题,有一种可靠的方法(假设您的应用程序没有使用多个线程),假设您的智能指针未包含的所有内容都不在堆上:

->重载 new,以便您可以存储分配的所有块的列表以及每个块的大小。
->当你的智能指针的构造函数时,在你的 this 指针所属的块中搜索。如果它不在任何块中,您可以说它“在堆栈上”(实际上,这意味着它不由您管理)。否则,您知道指针被分配的位置和时间(如果您不想寻找孤立指针和懒惰的释放内存,或类似的东西..)
它不依赖于架构。

To answer your question, a reliable way (assuming your aplication isn't using more thant one thread), assuming that everithing wich is not contained by your smart pointer isn't on the heap :

-> Overloading new, so that you ca store a list of all blocs allocated, with the size of each block.
-> When the constructor of your smart pointer, search in wich block your this pointer belong. If it isn't in any block, you can say it's "on the stack" (actualy, it means it's not managed by you). Otherwise, you know where and when your pointer was allocated (if you wan't to look for orphan pointers and lasily free memory, or things like that..)
It do not depend from the architechture.

输什么也不输骨气 2024-08-24 15:32:47

有一个解决方案,但它强制继承。请参阅 Meyers,“更有效的 C++”,第 27 条。

编辑:
Ron van der Wal 撰写的总结了 Meyers 的建议 ,Meyers 本人在他的博客中链接到该链接(在这篇文章中):

跟踪基于堆的对象

作为全局变量的替代方案
方法,Meyers 提出了一个 HeapTracked 类,它使用一个列表来保存
跟踪从堆中分配的类实例的地址,然后
使用此信息来确定特定对象是否驻留在
堆。实现过程如下:

类 HeapTracked {
  // 已分配地址的类全局列表
  typedef const void *RawAddress;
  静态列表地址;
民众:
  // 嵌套异常类
  类缺失地址{};

  // 允许dynamic_cast<>的虚拟析构函数;纯粹制作
  // HeapTracked 类抽象。
  虚拟~HeapTracked()=0;

  // 重载运算符new和delete
  静态无效*运算符新(size_t sz)
  {
    void *ptr=::operator new(sz);
    地址.push_front(ptr);
    返回指针;
  }

  静态 void 运算符删除(void *ptr)
  {
    // 从“地址”中删除“ptr”
    list::iterator it=find(addresses.begin(),

    地址.end(), ptr);
    if (it !=addresses.end()) {
      地址.擦除(it);
      ::运算符删除(ptr);
    } 别的
      抛出丢失地址();
  }

  // 堆检查特定对象
  bool isOnHeap() const
  {
    // 使用动态转换来获取对象块的开始
    RawAddress ptr=dynamic_cast(this);
    // 看看它是否在“地址”中
    返回 find(addresses.begin(), 地址.end(), ptr) !=
      地址.end();
  }
};

// Meyers 省略了第一个 HeapTracked:: 限定符...
列表 HeapTracked::地址; 

原始文章还有更多内容需要阅读:Ron van der Wal 对此建议进行了评论,然后演示了其他替代堆跟踪方法。

There is a solution, but it forces inheritance. See Meyers, "More Effective C++", Item 27.

EDIT:
Meyers' suggestion is summarized in an article written by Ron van der Wal, which Meyers himself linked to in his blog (in this post):

Tracking heap based objects

As an alternative to the global variable
approach, Meyers presents a HeapTracked class that uses a list to keep
track of the addresses of class instances allocated off the heap, then
uses this information to determine if a particular object resides on
the heap. The implementation goes like this:

class HeapTracked {
  // Class-global list of allocated addresses
  typedef const void *RawAddress;
  static list<RawAddress> addresses;
public:
  // Nested exception class
  class MissingAddress {};

  // Virtual destructor to allow dynamic_cast<>; pure to make
  // class HeapTracked abstract.
  virtual ~HeapTracked()=0;

  // Overloaded operator new and delete
  static void *operator new(size_t sz)
  {
    void *ptr=::operator new(sz);
    addresses.push_front(ptr);
    return ptr;
  }

  static void operator delete(void *ptr)
  {
    // Remove ‘ptr’ from ‘addresses’
    list<RawAddress>::iterator it=find(addresses.begin(),

    addresses.end(), ptr);
    if (it !=addresses.end()) {
      addresses.erase(it);
      ::operator delete(ptr);
    } else
      throw MissingAddress();
  }

  // Heap check for specific object
  bool isOnHeap() const
  {
    // Use dynamic cast to get start of object block
    RawAddress ptr=dynamic_cast<RawAddress>(this);
    // See if it’s in ‘addresses’
    return find(addresses.begin(), addresses.end(), ptr) !=
      addresses.end();
  }
};

// Meyers omitted first HeapTracked:: qualifier...
list<HeapTracked::RawAddress> HeapTracked::addresses; 

There is more to read on the original article: Ron van der Wal comments on this suggestion, and then demonstrates other alternative heap tracking methods.

阪姬 2024-08-24 15:32:47

看看这里的程序:http://alumni.cs.ucr。 edu/~saha/stuff/memaddr.html。通过一些转换,它输出:

        Address of main: 0x401090
        Address of afunc: 0x401204
Stack Locations:
        Stack level 1: address of stack_var: 0x28ac34
        Stack level 2: address of stack_var: 0x28ac14
        Start of alloca()'ed array: 0x28ac20
        End of alloca()'ed array: 0x28ac3f
Data Locations:
        Address of data_var: 0x402000
BSS Locations:
        Address of bss_var: 0x403000
Heap Locations:
        Initial end of heap: 0x20050000
        New end of heap: 0x20050020
        Final end of heap: 0x20050010

Take a look at the program here: http://alumni.cs.ucr.edu/~saha/stuff/memaddr.html. With a few casts, it ouputs:

        Address of main: 0x401090
        Address of afunc: 0x401204
Stack Locations:
        Stack level 1: address of stack_var: 0x28ac34
        Stack level 2: address of stack_var: 0x28ac14
        Start of alloca()'ed array: 0x28ac20
        End of alloca()'ed array: 0x28ac3f
Data Locations:
        Address of data_var: 0x402000
BSS Locations:
        Address of bss_var: 0x403000
Heap Locations:
        Initial end of heap: 0x20050000
        New end of heap: 0x20050020
        Final end of heap: 0x20050010
很酷不放纵 2024-08-24 15:32:47

有特定于平台的解决方案:

Windows:有查询堆栈范围的系统函数,请参阅问题
https://stackoverflow.com/q/3918375/9437799。利用这些堆栈变量可以被唯一地标识。

Posix: 同样,pthread_attr_getstack() 应该提供堆栈范围。

根据您的问题,不需要考虑数据段中的变量,否则您可能会迭代分配给进程的模块并查询它们的内存范围。

There are platform specific solutions:

Windows: There are system functions to query stack ranges, see question
https://stackoverflow.com/q/3918375/9437799 . With these stack variables may be uniquely identified.

Posix: Similiarily pthread_attr_getstack() should deliver stack ranges.

From your question variables in data segments do not need to be considered, else you might iterate over the modules allocated to the process and query their memory ranges.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文