C オブジェクトのメモリ レイアウト
質問:
C はメモリ内でどのように配置されますか?物体?動的キャストはオフセットを使用してメモリ内のオブジェクトのポインタを調整するだけですが、再解釈ではこのポインタに対してあらゆる操作を実行できると聞きました。よくわかりません。詳細を教えてください。
答え:
メモリ レイアウト
メモリ レイアウトは主に実装に依存します。重要な例外が 1 つあります。それは、同じアクセス指定子を持つメンバー変数が宣言順に配置されることです。
§ 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
クラスのレイアウト:
*** 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)
メンバー変数を項目化していません (または、少なくとも取得方法がわかりません)。 Clang レイアウトと同様に、オフセット 28 と 64 の間に配置する必要があります。
基本クラスがプライマリとして指定されていることがわかります。これにより、クラスが SBase1 としてアクセスされる場合、このポインター調整の必要がなくなります。
その他のコンパイラ ディレクティブ
次の同等のディレクティブは、さまざまなコンパイラに適用されます:
参照: https://blogs.msdn.microsoft.com/vcblog/2007/ 05/ 17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/
以上がC はメモリ内でオブジェクトをどのように配置しますか?また、それは動的なキャストと再解釈にとって何を意味しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。