具有函数的结构的c ++大小
c++ size of a struct with a function
结果显示 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;
}
函数foobar
不是对象的一部分。相反,它是已编译程序的一部分。调用函数时,机器码指的是它的地址。
sizeof()
将只考虑成员变量。
此外,非 vptr 方法不会影响结构的大小,因为它们不需要任何运行时支持。
您的 struct
与
相似
struct ABC_ {
int a;
int b;
int c;
};
int ABC_::foobar(int a) {
return a;
}
添加到现有答案:
另外值得注意的是,类 与虚拟方法相比,要大 8 个字节(或者无论您系统上的指针有多少字节)。这是一个指向 table 的指针,其中包含虚拟方法的地址。这就是程序在运行时如何知道要调用哪个版本的虚拟方法。
该函数存储在 .text
段内。
A compiled program’s memory is divided into five segments: text,
data, bss, heap, and stack. Each segment represents a special portion
of memory that is set aside for a certain purpose. The text segment is
also sometimes called the code segment. This is where the assembled
machine language instructions of the program are located.
对象本身的内存布局为:
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;
}
};
当你的 class 包含虚函数时,它们以相同的方式存储,但你的 class 的内存布局发生变化......它将有一个不可见的 4 字节(32 位)指针到虚函数 table 或虚方法 table/ VMT (这个 table 只是保存函数的地址以允许多态性,例如 table 是为每个 class 单独创建的,当它继承另一个 table 存储在内存中时)所以在这种情况下大小将为 16。它还取决于编译器的对齐设置...
如果你想获得指向 vtable 的指针,你可以这样做:
void **get_vtable(void *obj) {
return *(void ***)obj;
}
Vtable 通常存储在我所知道的每个编译器的开头。
通过查看函数的调用方式,您可以注意到函数为虚函数和非虚函数时的区别。普通函数直接 called/jmped 但虚拟函数,它们由存储在 table.
中的函数指针调用
(我脑子里的一些 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
了解事物如何存储在内存中的最佳方法是使用一些反汇编程序 and/or 调试器。我推荐 IDA Pro 和 x64dbg。
结果显示 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;
}
函数foobar
不是对象的一部分。相反,它是已编译程序的一部分。调用函数时,机器码指的是它的地址。
sizeof()
将只考虑成员变量。
此外,非 vptr 方法不会影响结构的大小,因为它们不需要任何运行时支持。
您的 struct
与
struct ABC_ {
int a;
int b;
int c;
};
int ABC_::foobar(int a) {
return a;
}
添加到现有答案:
另外值得注意的是,类 与虚拟方法相比,要大 8 个字节(或者无论您系统上的指针有多少字节)。这是一个指向 table 的指针,其中包含虚拟方法的地址。这就是程序在运行时如何知道要调用哪个版本的虚拟方法。
该函数存储在 .text
段内。
A compiled program’s memory is divided into five segments: text, data, bss, heap, and stack. Each segment represents a special portion of memory that is set aside for a certain purpose. The text segment is also sometimes called the code segment. This is where the assembled machine language instructions of the program are located.
对象本身的内存布局为:
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;
}
};
当你的 class 包含虚函数时,它们以相同的方式存储,但你的 class 的内存布局发生变化......它将有一个不可见的 4 字节(32 位)指针到虚函数 table 或虚方法 table/ VMT (这个 table 只是保存函数的地址以允许多态性,例如 table 是为每个 class 单独创建的,当它继承另一个 table 存储在内存中时)所以在这种情况下大小将为 16。它还取决于编译器的对齐设置...
如果你想获得指向 vtable 的指针,你可以这样做:
void **get_vtable(void *obj) {
return *(void ***)obj;
}
Vtable 通常存储在我所知道的每个编译器的开头。
通过查看函数的调用方式,您可以注意到函数为虚函数和非虚函数时的区别。普通函数直接 called/jmped 但虚拟函数,它们由存储在 table.
中的函数指针调用(我脑子里的一些 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
了解事物如何存储在内存中的最佳方法是使用一些反汇编程序 and/or 调试器。我推荐 IDA Pro 和 x64dbg。