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中文網其他相關文章!