簡體   English   中英

C ++編譯器 - 解析類成員的名稱

[英]C++ compiler - resolving name of a class member

當編譯器看到這段代碼時:

SomeClass foo;
int x = foo.bar;

檢索bar值的過程是什么? 即它看一些表示類定義的數據結構? 如果是這樣的數據結構是在編譯時還是在運行時生成的?

編譯器的地址為foo 在該地址處,有足夠的空間用於成員變量( sizeof(SomeClass) ),其中可能包含一些填充。

它知道`bar在類中的某個位置(通常是它們被聲明的順序,加上一些其他魔法,如繼承),並跳轉到該偏移量。

那是:

struct SomeClass
{
    short s;
    float f;
    int bar;
    char *c;
}

// pseudo-code:
&SomeClass.bar == (&SomeClass) + sizeof(short) + sizeof(float);

在運行時,它獲取該數據,並將其分配給x

在編譯時,編譯器將有一些數據結構,告訴它如何訪問SomeClass的每個成員。 對於簡單的情況,它只是一個偏移量,但如果你有非平凡的繼承,可能會有更多。

為了處理表達式,編譯器會查詢此內部數據並(最終)發出適當的機器代碼。 通過運行時,這個結構將被拋棄,剩下的就是從foo的地址開始,為了做任何需要而發出的代碼。 但是,如果你有一個指向bar的成員指針,那么如何訪問bar成員的細節在某種程度上被封裝在那個指針值中(可能是一個偏移,也許更復雜)。

當編譯器看到SomeClass的定義時,該過程開始。 基於該定義,它構建了一個內部結構,其中包含SomeClass字段的類型,以及SomeClass方法的代碼位置。

當你寫SomeClass foo; 編譯器找到與SomeClass構造函數對應的代碼,並創建調用該代碼的機器指令。 在下一行,你寫int x = foo.bar 這里編譯器編寫機器指令為int分配堆棧空間,然后查看SomeClass數據結構。 該數據結構將告訴它從foo對象的開頭到bar字節偏移量。 然后編譯器寫入機器代碼以將對應於bar的字節復制到x的存儲器中。 所有這些機器代碼都寫入您的可執行文件。

通常,一旦編譯完成,表示SomeClass和其他定義的數據結構將被丟棄。 你剩下的只是一套機器指令。 這些指令在您實際運行程序時執行,因此SomeClass的構造函數和將foo.bar復制到x的代碼由CPU執行,而不會明確了解對象的結構。

這是一般情況。 當您在調試器下運行代碼並進行優化時,會出現一些特殊情況,但這通常會發生這種情況。

您必須認為在編譯期間,每個類都會轉換為結構(以簡化說明),所以如果您有

class Foo
{
   int x, y, z;
   char bar[10];
   ... etc ...
}

它們被轉換為具有指定大小的結構,在這種情況下為4 * 3 + 10個字節。 然后它根據對齊方式以更方便的方式排列它們,記住例如在偏移4處你可以找到屬性y,而在地址8你可以找到z。

然后它很簡單,只需將4添加到分配所涉及的類的地址,然后獲取y的地址,依此類推。

編譯器僅在編譯時存儲此類類元數據。 你的第一個問題是,它如何檢索bar的值,實際上非常復雜。 您可以將其視為計算bar與對象foo的偏移量,然后讀取該位置的內存。 然而,根據x的實際使用方式,它可以做一些不同的事情。 在某些情況下,“x”可能根本不會出現在編譯代碼中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM