结果显示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;
}
答案 0 :(得分:3)
函数foobar
不是对象的一部分。相反,它是已编译程序的一部分。调用该函数时,机器代码引用其地址。
答案 1 :(得分:3)
sizeof()
将仅考虑成员变量。
此外,非vptr方法对struct的大小没有贡献,因为它们不需要任何运行时支持。
您的struct
与
struct ABC_ {
int a;
int b;
int c;
};
int ABC_::foobar(int a) {
return a;
}
答案 2 :(得分:3)
该功能存储在.text
段内。
编译程序的内存分为五个部分:文本, 数据,bss,堆和堆栈。每个细分代表一个特殊部分 为某种目的而留出的记忆。文本段是 有时也称为代码段。这是组装的地方 该程序的机器语言指令位于。
对象本身的内存布局是:
class ABC_ {
public:
int a; // 0x4 (4)
int b; // 0x8 (8)
int c; // 0xC (12)
int foobar(int a) { // you can print address using &foobar
return a;
}
};
当你的类包含虚函数时,它们以相同的方式存储,但你的类的内存布局发生了变化......它将有一个不可见的4字节(32位)指向虚函数表或虚方法的指针table / VMT (这个表只保存允许多态的函数的地址,这样的表是为每个类分别创建的,当它继承另一个表存储在内存中)所以在这种情况下,大小将是16.它还取决于编译器的对齐设置......
如果你想获得指向vtable的指针,你可以这样做:
void **get_vtable(void *obj) {
return *(void ***)obj;
}
Vtable通常存储在我知道的每个编译器的开头。
你可以注意到功能是虚拟的,而不是通过查看它被调用的方式。正常函数直接调用/ jmped但是虚函数,它们由存储在表中的函数指针调用。
(某些x86 asm在我的脑海里,可能是错的)
mov edx, [ecx] // ecx = this pointer
add edx, 12h // let's say 0x12 is the offset divided by 4 is 4 = index in vtable
call edx // you know it's virtual function
或只是
mov edx, [ecx+12h]
call edx
了解内存如何存储在内存中的最佳方法是使用一些反汇编程序和/或调试程序。我推荐IDA Pro和x64dbg。
答案 3 :(得分:2)
添加到现有答案:
另外值得注意的是,使用虚方法的类大8个字节(或者系统上的指针有多少个字节)。这是一个指向具有虚拟方法地址的表的指针。这是程序在运行时知道要调用哪个版本的虚拟方法。