【问题标题】:Where are functions of an object stored in memory?对象的函数存储在内存中的什么位置?
【发布时间】:2014-07-01 07:40:18
【问题描述】:

假设我们有一个类:

class Foo
{
private:
    int a;
public:
    void func()
    {
       a = 0;
       printf("In Func\n");
    }
}

int main()
{
    Foo *foo = new Foo();
    foo->func();
    return 0;
}

当Foo类的对象被创建和初始化时,我知道整数a会占用4个字节的内存。函数是如何存储的?调用 foo->func() 时,内存/堆栈/寄存器/程序计数器会发生什么?

【问题讨论】:

    标签: c++ memory


    【解决方案1】:

    简短的回答:它只会在二进制文件的文本或代码部分存储一次,而与创建的类实例的数量无关。

    函数不会为类的每个实例单独存储在任何地方。它们的处理方式与任何其他非成员函数相同。唯一的区别是编译器实际上给函数增加了一个额外的参数,它是一个类类型的指针。 例如编译器会生成这样的函数原型:

    void func(Foo* this);
    

    (请注意,这可能不是最终签名。最终签名可能会更加神秘,具体取决于包括编译器在内的各种因素)

    任何对成员变量的引用都将被替换为

    this-><member> //for your ex. a=0 translates to this->a = 0;
    

    所以 foo->func();大致翻译为:

    1. 将 Foo* 的值压入堆栈。 #编译器依赖
    2. 调用 func 将导致指令指针跳转到可执行文件中 func 的偏移量 #architecture 相关读取 thisthis
    3. Func 将从堆栈中弹出值。对成员变量的任何进一步引用都将在取消引用该值之前进行

    【讨论】:

    • +1;至于您提到术语 signature 的原因,有时会使用替代的 prototype,尽管这里的这种用法可以争论。
    • 既然我也提到了返回类型,原型应该是写字。编辑答案以反映相同。
    • 这么好的答案
    【解决方案2】:

    您的函数不是虚拟的,因此它是静态调用的:编译器插入一个跳转到与您的函数对应的代码段。每个实例不使用额外的内存。

    如果您的函数是虚拟的,您的实例将携带一个 vpointer,该 vpointer 将被取消引用以找到其类的 vtable,然后将索引该 vtable 以找到要调用的函数指针,并最终跳转到那里。因此,额外的成本是每个类一个 vtable(可能是一个函数指针的大小,乘以类的虚函数数),以及每个实例一个指针。

    请注意,这是虚拟调用的常见实现,但标准并未强制执行,因此实际上根本不能这样实现,但您的机会很大。如果编译器在编译时知道实例的静态类型,它通常也可以完全绕过虚拟调用系统。

    【讨论】:

    • “编译器插入到代码段的跳转”。这个跳转信息存储在哪里?
    • @shaveenk 直接在调用站点,即代码段的另一部分。对于静态调用,它会被硬编码,所以你最终会得到一个普通的 goto 0xSomewhere;在程序集中(经过一些参数调整)
    【解决方案3】:

    成员函数就像常规函数一样,它们存储在“代码”或“文本”部分中。 (非静态)成员函数有一个特别之处,那就是传递给函数的“隐藏”this 参数。因此,在您的情况下,foo 中的地址将传递给func

    该参数的确切传递方式以及寄存器和堆栈发生的情况由 ABI(应用程序二进制接口)定义,并且因处理器而异。对此没有严格的定义,除非您告诉我们正在使用的编译器、操作系统和处理器的组合是什么(并假设信息是公开的——并非所有编译器/操作系统供应商都会非常清楚地说明这一点)。例如,x86-64 在 WINDOWS 上将 RCX 用于 this,在 Linux 上使用 RDI,调用指令会自动将返回地址压入堆栈。在 ARM 处理器上 [在 Linux 中,但我认为这同样适用于 Windows,我只是从未看过],R0 用于this 指针,BX 指令用于调用,它作为其自身的一部分将lr 与要返回的指令的pc 一起存储。 lr 然后必须保存在 [可能在堆栈上] 在 func 中,因为它调用 printf

    【讨论】:

      猜你喜欢
      • 2020-02-07
      • 1970-01-01
      • 2021-01-17
      • 2022-01-07
      • 2021-10-17
      • 2010-11-20
      • 2013-04-24
      • 2019-08-13
      • 2011-02-21
      相关资源
      最近更新 更多