首頁  >  文章  >  後端開發  >  C 如何在記憶體中排列對象,這對於動態轉換和重新解釋意味著什麼?

C 如何在記憶體中排列對象,這對於動態轉換和重新解釋意味著什麼?

DDD
DDD原創
2024-11-02 03:52:30307瀏覽

How does C   arrange objects in memory, and what does it mean for dynamic casting and reinterpreting?

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=((&amp; Class::_ZTV5Class) + 24u)
  SBase1 (0x0x141f78840) 0
      primary-for Class (0x0x141f81280)
  SBase2 (0x0x141f788a0) 16
      vptr=((&amp; Class::_ZTV5Class) + 56u)
  SBase3 (0x0x141f78900) 28
  VBase (0x0x141f78960) 64 virtual
      vptridx=8u vbaseoffset=-24 vptr=((&amp; Class::_ZTV5Class) + 88u)

它沒有逐項列出成員變量(或至少我不知道如何獲取),但你可以看出它們必須位於偏移量28 和64 之間,就像clang 佈局一樣。

你可以看到一個基類被指定為 primary。當 Class 被存取為 SBase1 時,這取消了 this 指標調整的需要。

其他編譯器指令

以下等價指令適用於不同編譯器:

  • gcc:$ g -fdump-class- hierarchy -c layout.cpp
  • Visual C :cl main.cpp /c /d1reportSingleClassLayoutTest_A

見:https://blogs.msdn.microsoft.com/vcblog/2007 05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/

以上是C 如何在記憶體中排列對象,這對於動態轉換和重新解釋意味著什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn