C 对象的内存布局
问题:
C 在内存中是如何布置对象的?听说动态强制转换只调整对象在内存中的指针,带偏移量;而重新解释允许我们对此指针做任何操作。我不太理解。请提供详细信息!
解答:
内存布局
内存布局主要取决于实现。但有一个关键例外,即具有相同访问说明符的成员变量将按声明顺序排列。
§ 9.2.14 非静态数据成员(非联合)具有相同访问控制权的类(Clause 11)被分配,以便后续成员在类对象中具有更高的地址。具有不同访问控制权的非静态数据成员的分配顺序未指定(11)。实现对齐要求可能导致两个相邻成员不会立即相互分配;管理虚拟函数(10.3)和虚拟基类(10.1)的空间要求也可能导致这种情况。
其他内存管理
除了成员变量之外,类或结构还需要为成员变量、基类的子对象、虚拟函数管理(例如虚拟表)以及这些数据的填充和对齐提供空间。这取决于实现,但 Itanium ABI 规范是一种流行的选择。gcc 和 clang 遵循它(至少在一定程度上)。
http://mentorembedded.github.io/cxx-abi/abi.html#layout
Itanium ABI
当然,Itanium ABI 不是 C 标准的一部分,也没有约束力。要获得更详细的信息,你需要查阅实现者的文档和工具。clang 提供了一个工具来查看类的内存布局。例如,以下内容:
class VBase { virtual void corge(); int j; }; class SBase1 { virtual void grault(); int k; }; class SBase2 { virtual void grault(); int k; }; class SBase3 { void grault(); int k; }; class Class : public SBase1, SBase2, SBase3, virtual VBase { public: void bar(); virtual void baz(); // 不允许虚拟成员函数模板,原因考虑内存布局和虚表 // template<typename T> // virtual void quux(); private: int i; char c; public: float f; private: double d; public: short s; }; class Derived : public Class { virtual void qux(); }; int main() { return sizeof(Derived); }
在创建使用类内存布局的源文件后,clang 将显示内存布局。
$ clang -cc1 -fdump-record-layouts layout.cpp
Class 的布局:
*** Dumping AST Record Layout 0 | class Class 0 | class SBase1 (primary base) 0 | (SBase1 vtable pointer) 8 | int k 16 | class SBase2 (base) 16 | (SBase2 vtable pointer) 24 | int k 28 | class SBase3 (base) 28 | int k 32 | int i 36 | char c 40 | float f 48 | double d 56 | short s 64 | class VBase (virtual base) 64 | (VBase vtable pointer) 72 | int j | [sizeof=80, dsize=76, align=8 | nvsize=58, nvalign=8]
更多内存布局信息
更多有关此 clang 特性的信息可以在 Eli Bendersky 的博客上找到:
http://eli.thegreenplace.net/2012/12/17/dumping-a-c-objects-memory-layout-with-clang/
gcc 提供了一个类似的工具 `-fdump-class-hierarchy'。对于上面给出的类,它输出(除其他内容外):
Class Class size=80 align=8 base size=58 base align=8 Class (0x0x141f81280) 0 vptridx=0u vptr=((& Class::_ZTV5Class) + 24u) SBase1 (0x0x141f78840) 0 primary-for Class (0x0x141f81280) SBase2 (0x0x141f788a0) 16 vptr=((& Class::_ZTV5Class) + 56u) SBase3 (0x0x141f78900) 28 VBase (0x0x141f78960) 64 virtual vptridx=8u vbaseoffset=-24 vptr=((& Class::_ZTV5Class) + 88u)
它没有逐项列出成员变量(或者至少我不知道如何获取),但你可以看出它们必须位于偏移量 28 和 64 之间,就像 clang 布局中一样。
你可以看到一个基类被指定为 primary。当 Class 被作为 SBase1 访问时,这取消了 this 指针调整的需要。
其他编译器指令
以下等价指令适用于不同编译器:
见:https://blogs.msdn.microsoft.com/vcblog/2007/05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/
以上是C 如何在内存中排列对象,这对于动态转换和重新解释意味着什么?的详细内容。更多信息请关注PHP中文网其他相关文章!