堆栈变量的变量/引用名称或类型存储在内存中的哪里?

3

我认为我理解了堆栈和堆之间的主要区别。

在下面的程序中,一个大小为n的对象被创建在堆上。一个指针p指向这个无名对象被创建在堆栈上,它占用4个字节(至少在我的系统上)。如果我理解正确,由于引用不使用额外的内存,除了可能在堆栈上返回main()函数的int值之外,不会分配更多的内存。

Class Object;  // n bytes

int main() {
    Object* p = new Object();
    Object& r = *p;
    // ...
}

然而,内存管理仍不完全清楚:

1)变量p和r的名称存储在哪里?它们都是局部变量,所以我认为它们也应该放在堆栈上?这难道不需要额外的内存来存储一个变量名和它引用到的内存部分之间的绑定关系吗?

2)指针的类型存储在哪里?指针仅占据堆栈上的4个字节,这(我认为)是存储内存地址的精确大小。计算机如何知道可以在该地址找到哪种类型?

3)与(2)类似,堆上的Object需要n个字节的存储空间,而对它的(直接)引用需要0个字节。此对象的类型存储在哪里,因此当使用r时,它知道它是哪种类型?

4)我了解到编译的程序也驻留在某个地方的内存中以指导其执行。这是在堆栈还是堆上,或者这仍然是内存的另一部分?


你是否想知道 p*p 的类型?因为在派生类中,p 也可能指向较大对象内的基类子对象。 - MSalters
3个回答

7

变量名是静态的,在运行时不可用。编译器知道变量将被存储的位置,并生成访问该内存位置的代码,无需名称。

它们可能会在程序文件的特殊调试部分中可用,以允许调试器显示变量的值。

指针的类型也是静态的(除了与多态类类型相关的有限动态类型信息之外,但不包括指针类型)。编译器知道类型,并生成访问存储的值的代码,以正确方式处理该类型。

如果类型是多态的(即如果它是带有至少一个虚函数的类类型),则将存在一些静态数据,存储在无法直接访问的未指定位置中,以描述该类型。将有足够的数据支持虚函数调用(通常是指向最终覆盖的指针表)和RTTI(用于dynamic_cast的继承结构的规范,以及通过typeid可用的type_info结构)。

否则,所有类型信息都是静态的。

在典型计算机上,它位于静态内存(代码或文本部分),在程序启动时加载。在嵌入式系统上,它可能会更永久地位于只读存储器中。


1
好的,有运行时类型信息(RTTI)-因为并非所有类型都是完全静态的。面向对象编程允许多态性。但指针本身从不具备多态性。 - MSalters
@MSalters:确实,我有点过于简化了。 - Mike Seymour
1
重新阅读后,我认为问题本身就是含糊不清的。它还在想“哪种类型可以在那个地址找到?”,也就是说,它肯定在想指向的对象。然后RTTI肯定是相关的。我们不知道Object是否具有多态性。 - MSalters
1
@MSalters:说得好,也许问题3需要自己的答案。 - Mike Seymour

3
由于引用不使用额外内存,因此不会分配更多内存。
引用的实现并未在C++标准中指定,但大多数编译器会像指针一样实现它们,因此在未优化的代码中可能会为r再分配4个字节(在您的系统上)。 p和r的名称存在于编译器内部,在其运行时以及在生成的对象/库/程序中可能存在一些调试符号信息,以帮助交互式调试(例如使用GCC的"g++-g"选项),但它们不会通过正常的C++程序语句存储或访问。
编译的程序是一堆二进制数据和机器代码操作码(数字),操作系统知道如何加载并要求CPU解释和执行。该数据通常不在堆栈或堆上,而是在操作系统排列的“未初始化数据”,“已初始化数据”和“代码”段/区域中。

1
计算机永远不会知道p和r。 变量名用于提高高级语言的可读性。 例如,您可以通过

获取汇编代码。
gcc -S -c code.c

代码中根本没有p和r。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接