解析c 靜態聯編和類的成員函式呼叫

2021-08-31 20:41:18 字數 1167 閱讀 5784

只要學了c++的人,肯定知道靜態聯編和動態聯編,如果你不知道,ok那你學習之路還長。簡單的靜態聯編的東西就不說了。先看下面程式。

class aa;

};int main()

上面程式執行會報錯嗎?

如果你說執行一切正常並知道原因,ok。那就別往下看了,時間就是金錢。

確實,這個執行正常並輸出 surprise? 不信?你copy過去執行下試試。為啥啊。明明指標p的值是null,而你使用null指標去呼叫成員函式,明明會報記憶體錯誤的瑟。書上不是說了不能使用 null指標嗎?嘿嘿,沒錯,確實不能使用null指標,但是這裡,程式根本就沒有用指標p的值,而是僅僅用到了它的型別做靜態束定而已。

要解此題首先要明確兩個問題。

1、靜態聯編的原理;2、成員函式的**在執行期只有乙份拷貝。

靜態聯編簡單的說就是在編譯期就已經確定了要呼叫哪個函式了,這裡的result()就是。同時要知道,類的成員函式在執行期只有乙份拷貝在記憶體,不管類的例項有多少個,成員函式始終只有乙份**在記憶體,因此只要知道類的指標的型別之後,就可以定位到函式的入口位址,根本不關心該指標指向的是乙個什麼東西。成員函式和成員變數不一樣,非靜態成員變數是跟隨類的例項走的。

ok,明白上面兩個問題之後,這個事情就好解決了。直接上彙編吧。

彙編如下:

aa *p = null;

00411ace mov dword ptr [p],0

p->result();

00411ad5 mov ecx,dword ptr [p]

00411ad8 call aa::result (41105ah)

清楚了吧。在執行p->result()的時候只是把p的值移動到了乙個暫存器裡面,但是並沒有用到這個值,後面就直接呼叫aa::result函式了,0x41105a正是該函式的入口位址。

ok,好了。不僅可以向以上說的去訪問成員函式,甚至再過分一點((a*)0)->result();這樣都可以。你再火一點把那個0換成任意乙個位址都可以正確呼叫到那個函式,因為編譯器在靜態束定的時候只關心那個指標的型別。當然了,不可這樣去訪問類的成員變數,因為成員變數是在物件的記憶體布局裡面的。

值得說一點的是,如果你在result函式裡面有涉及到類的成員變數的訪問,那麼這顯然就會出錯了,因為成員變數需要通過傳進來的this指標(其實就可以理解成時p指標)去訪問物件的記憶體的。然而此時p還沒有指向乙個有效的空間。故而出錯。

解析c 靜態聯編和類的成員函式呼叫

只要學了c 的人,肯定知道靜態聯編和動態聯編,如果你不知道,ok那你學習之路還長。簡單的靜態聯編的東西就不說了。先看下面程式。class aa int main 上面程式執行會報錯嗎?如果你說執行一切正常並知道原因,ok。那就別往下看了,時間就是金錢。確實,這個執行正常並輸出 surprise?不信...

深入解析c 靜態聯編和類的成員函式呼叫

只要學了c 的人,肯定知道靜態聯編和動態聯編,如果你不知道,ok那你學習之路還長。簡單的靜態聯編的東西就不說了。先看下面程式。class aa int main 上面程式執行會報錯嗎?如果你說執行一切正常並知道原因,ok。那就別往下看了,時間就是金錢。確 實,這個執行正常並輸出 surprise?不...

C 靜態聯編和動態聯編

聯編就是將模組或者函式合併在一起生成可執行 的處理過程,同時對每個模組或者函式呼叫分配記憶體位址,並且對外部訪問也分配正確的記憶體位址,它是電腦程式彼此關聯的過程。按照聯編所進行的階段不同,可分為兩種不同的聯編方法 靜態聯編和動態聯編。靜態聯編是指在編譯階段就將函式實現和函式呼叫關聯起來,因此靜態聯...