C++ 具有函数的结构体的大小

Pet*_*ang 3 c++ struct sizeof

结果说12
该函数foobar存储在内存中的什么位置?

#include <iostream>
using namespace std;
struct ABC_ {
    int a;
    int b;
    int c;
    int foobar(int a) {
        return a;
    }
};
int main() {
    ABC_ ABC;
    cout << sizeof ABC;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Kon*_*rad 5

该函数存储在.text段内。

\n\n
\n

编译后的程序\xe2\x80\x99的内存分为五个段:文本段、数据段、bss段、堆段和堆栈段。每个段代表为特定目的而留出的特殊内存部分。文本段有时也称为代码段。这是程序的汇编机器语言指令所在的位置。

\n
\n\n

对象本身的内存布局是:

\n\n
class ABC_ {\npublic:\n    int a; // 0x4 (4)\n    int b; // 0x8 (8)\n    int c; // 0xC (12)\n    int foobar(int a) { // you can print address using &foobar\n        return a;\n    }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

当你的类包含虚函数时,它们以相同的方式存储,但类的内存布局发生变化...它将有一个不可见的 4 字节(32 位)指针,指向虚函数表或虚方法表/ VMT(此table 只是保存函数的地址以允许多态性,这样的表是为每个类单独创建的,当它继承另一个表时存储在内存中),因此在这种情况下大小将为 16。它还取决于编译器的对齐设置。 ..

\n\n

如果你想获取指向 vtable 的指针,可以这样做:

\n\n
void **get_vtable(void *obj) {\n    return *(void ***)obj;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在我所知道的每个编译器中,Vtable 通常存储在开头。

\n\n

通过查看函数的调用方式,您可以注意到函数为虚拟函数和非虚拟函数时的差异。普通函数是直接调用/跳转的,但虚拟函数是通过存储在其表中的函数指针来调用的。

\n\n

(我脑子里有些x86 asm,可能是错的)

\n\n
mov edx, [ecx] // ecx = this pointer\nadd edx, 12h // let's say 0x12 is the offset divided by 4 is 4 = index in vtable\ncall edx // you know it's virtual function\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者简单地

\n\n
mov edx, [ecx+12h]\ncall edx\n
Run Code Online (Sandbox Code Playgroud)\n\n

了解事物如何存储在内存中的最佳方法是使用一些反汇编器和/或调试器。我推荐 IDA Pro 和 x64dbg。

\n