我了解到,在大多数操作系统中,内存地址是从最高位到最低位排列的。因此,我想知道堆、栈和全局内存是否都属于相同的排序方式..?
如果我创建了...
pointerType* pointer = new pointerType //creates memory address 0xffffff
然后在堆栈上创建了一个本地变量。
localObject object
本地对象的地址是否为0xfffffe?
或者堆栈的排序完全不同。
我了解到,在大多数操作系统中,内存地址是从最高位到最低位排列的。因此,我想知道堆、栈和全局内存是否都属于相同的排序方式..?
如果我创建了...
pointerType* pointer = new pointerType //creates memory address 0xffffff
然后在堆栈上创建了一个本地变量。
localObject object
本地对象的地址是否为0xfffffe?
或者堆栈的排序完全不同。
堆和栈通常在内存中的两个非常不同的位置。
通常情况下,您会发现堆栈从某个起始地址向下增长,而堆从完全不同的起始地址向上增长。
然而,堆栈和堆(在C++标准中称为动态存储)的确切工作方式是由实现定义的,并不受C++标准的约束。
这取决于情况。在典型的 CPU 上,您拥有一个地址空间来存储所有内容,因此任何两个变量必须具有不同的地址。但是,大多数 CPU 支持虚拟寻址,这种情况下可能会出现两个不同的虚拟地址指向同一个物理地址。
然而,在 DSP(例如)上,通常有两到三个完全独立的地址空间 -- 例如,代码和数据将具有完全独立的物理 寻址(即,一个用于数据的内存芯片集连接到一个内存总线上,另一个用于代码的芯片集连接到另一条总线上)。在这种情况下,一个物理地址可能会引用内存的两个不同部分; 如果不知道它要引用的类型,则该地址可能根本无法区分这两个部分。
pointerType* pointer = new pointerType //创建内存地址0xffffff
你误解了0xffffff
。它不是新分配的内存地址,而是指针变量本身的地址。如果你想检查内存分配的位置,需要检查存储在0xffffff
中的值。
栈和堆并不是互相排斥的。想象这两种假设的编译器实现:
void PreMain()
{
char initialHeap[initialHeapSize]
HeapPointer heapHead = &initialHeap;
...
int returncode = main(argc, argv);
...
}
void PreMain()
{
void * stack = GetFromOSHeap(stackSize);
// some assembly intrinsic to replace the stack pointer
...
int returncode = main(argc, argv);
...
}
你可能在主流编译器中找不到这些,但我敢打赌肯定有某个嵌入式系统是这样工作的。
指针本身和局部对象都位于栈上。指针所指向的对象位于堆上。
这就是为什么在 C 中经常说只有传值。当你将指针传递给函数时,与传递 int 没有任何区别:函数参数接收端上的指针/int 是栈上的另一 "个" 变量。然而,由于指针的值(指向堆对象的地址)被复制到接收端,因此可以访问相同的堆对象。
你可以随时检查一下。这是其中一件事情,你可以通过输出值并检查它来找出答案。这并不能保证在所有计算机或编译器上都有相同的行为,但你可以看看你的情况如何。只需printf("0x%x\n", &variable)以查看变量的地址。在堆上分配一些东西,在栈上分配一些东西,然后检查它们的所有地址,你就会看到它们的位置以及每个地址向哪个方向扩展。
我通常会在我使用的每种语言中保留一个测试项目,只是为了快速添加一些内容,以便自己看看它是如何工作的。这样做非常适合像这样的情况,你甚至比StackOverflow提供答案更快得到你的答案。