c 底層剖析(1)

2021-09-30 10:26:35 字數 3130 閱讀 7530

首先從帶有虛函式的基類派生講起。

class base

virtual ~base()

virtual void say()

int base;

};class derive : public base

virtual ~derive()

virtual void say()

int derive;

};int _tmain(int argc, _tchar* ar**)

這是乙個很簡單的派生的例子,首先從記憶體角度看下,期中0x003b94b0為指標pd的值

可以看到最開始的四個位元組的值為0x00417700, 後面是兩個int型值分別為1和2,代表著base和derive的值,這兩個值是在建構函式裡進行賦值的,現在主要看下0x00417700這個值代表著什麼?

0x00417700這個記憶體位置的值是0x004112c6,在繼續跟下0x004112c6這個記憶體位置有什麼東西

004112c6  jmp         derive::`scalar deleting destructor' (414980h) 

可以看到這個地方是跳到乙個好像是derive的析構函式處,其實進去之後會發現其實他是乙個**函式,在此函式中先呼叫derive的析構函式,然後在呼叫operator delete 釋放記憶體。可以通過反彙編**來看下:

derive::`scalar deleting destructor':

00414980  push        ebp  

。。。。

0041499f  pop         ecx  

004149a0  mov         dword ptr [ebp-8],ecx 

004149a3  mov         ecx,dword ptr [this] 

004149a6  call        derive::~derive (4112b2h) 

004149ab  mov         eax,dword ptr [ebp+8] 

004149ae  and         eax,1 

004149b1  je          derive::`scalar deleting destructor'+3fh (4149bfh) 

004149b3  mov         eax,dword ptr [this] 

004149b6  push        eax  

004149b7  call        operator delete (4110d2h) 

中間的省略掉了,無關緊要,主要是將開闢的一段棧空間的內容初始化為0xcccccccc,在紅色處可以看到derive的析構函式的呼叫。現在在回到開頭處,用一張圖示意下

可以看到derive型別的物件的記憶體布局,首先是乙個虛表指標,然後是基類的成員變數最後才是自己的成員變數

現在來**下這個指向虛表的指標式什麼時候安插到物件的頭部的,我們通過派生類的建構函式來看下:

derive()

004116a0  push        ebp  

。。。。。。

004116bf  pop         ecx  

004116c0  mov         dword ptr [ebp-8],ecx    //ecx為this的值

004116c3  mov         ecx,dword ptr [this] 

004116c6  call        base::base (41115eh) 

004116cb  mov         eax,dword ptr [this] 

004116ce  mov         dword ptr [eax],offset derive::`vftable' (417700h) 

通過**建構函式的反彙編**可以看到,在派生類的建構函式中先是呼叫基類base的建構函式,現在我們跟到基類的建構函式中去:

base():

004117b0  push        ebp  

。。。。。

004117cf  pop         ecx  

004117d0  mov         dword ptr [ebp-8],ecx 

004117d3  mov         eax,dword ptr [this] 

004117d6  mov         dword ptr [eax],offset base::`vftable' (417718h) 

004117dc  mov         eax,dword ptr [this] 

004117df  mov         dword ptr [eax+4],1 

004117e6  push        offset string "base!\n" (417708h) 

004117eb  mov         eax,dword ptr [__imp_std::cout (41b328h)] 

004117f0  push        eax  

004117f1  call        std::operator<<> (4111a4h) 

通過基類的建構函式可以看到,他將offset base::`vftable' (417718h)基類的虛表位址賦給了物件的頭四個位元組,然後才是執行基類建構函式中的**,現在我們可以看到pd頭部的四個位元組的值不是417700h而是417718h,奇怪了別急,後面會看到417700h這個值是賦給pd頭部的四個位元組。基類的建構函式執行完畢之後回到派生類的建構函式,此事可以看到緊接著就是兩個賦值語句

004116cb  mov         eax,dword ptr [this] 

004116ce  mov         dword ptr [eax],offset derive::`vftable' (417700h) 

首先是將this指標的值賦給eax,然後將offset derive::`vftable' (417700h)派生類的虛表的指標賦給eax所指向的位址的頭四個位元組,也就是賦給pd所指的派生類物件的頭四個位元組,現在到此也就分析完了其記憶體布局,以及虛表指標的賦值過程。

Volatile底層原理剖析

基礎知識回顧 還是那句話,無論語言再怎麼牛,其都是對底層計算機指令的封裝。計算機cpu執行指令的時候是非常快的,如果每執行乙個指令都從記憶體中取資料的話,那會非常慢,嚴重影響cpu的執行速度,所以每個cpu都有自身對應的高速緩衝區 多級暫存器 每個執行緒被執行的時候,會先把執行時需要的資料複製到告訴...

HashMap底層原理簡單剖析

1 hashmap的儲存結構 陣列 鍊錶 紅黑樹 jdk1.8 如下圖所示 2 hashmap的特點,如何實現 我們知道hashmap是一種可以快速儲存很快速查詢的鍵值容器,那麼jdk是如何實現hashmap的快速儲存和快速查詢呢?我們先從陣列和鍊錶以及二叉查詢樹這三種資料結構說起 1 陣列 陣列結...

深度剖析Spring Cloud底層原理

毫無疑問,spring cloud 是目前微服務架構領域的翹楚,無數的書籍部落格都在講解這個技術。不過大多數講解還停留在對 spring cloud 功能使用的層面,其底層的很多原理,很多人可能並不知曉。實際上,spring cloud 是乙個全家桶式的技術棧,它包含了很多元件。本文先從最核心的幾個...