編譯器一般使用堆疊實現函式呼叫。堆疊是儲存器的乙個區域,嵌入式環境有時需要程式設計師自己定義乙個陣列作為堆疊。windows為每個執行緒自動維護乙個堆疊,堆疊的大小可以設定。編譯器使用堆疊來堆放每個函式的引數、區域性變數等資訊。
函式呼叫經常是巢狀的,在同一時刻,堆疊中會有多個函式的資訊,每個函式占用乙個連續的區域。乙個函式占用的區域被稱作幀(frame)。
編譯器從高位址開始使用堆疊。 假設我們定義乙個陣列a[1024]作為堆疊空間,一開始棧頂指標指向a[1023]。如果棧裡有兩個函式a和b,且a呼叫了b,棧頂指標會指向函式b的幀。如果函式b返回。棧頂指標就指向函式a的幀。如果在棧裡放了太多東西造成溢位,破壞的是a[0]上面的東西。
在多執行緒(任務)環境,cpu的堆疊指標指向的儲存器區域就是當前使用的堆疊。切換執行緒的乙個重要工作,就是將堆疊指標設為當前執行緒的堆疊棧頂位址。
不同cpu,不同編譯器的堆疊布局、函式呼叫方法都可能不同,但堆疊的基本概念是一樣的。
函式呼叫約定包括傳遞引數的順序,誰負責清理引數占用的堆疊等,例如 :
引數傳遞順序
誰負責清理引數占用的堆疊
__pascal
從左到右
呼叫者__stdcall
從右到左
被調函式
__cdecl
從右到左
呼叫者呼叫函式的**和被調函式必須採用相同的函式的呼叫約定,程式才能正常執行。在windows上,__cdecl是c/c++程式的預設函式呼叫約定。
在有的cpu上,編譯器會用暫存器傳遞引數,函式使用的堆疊由被調函式分配和釋放。這種呼叫約定在行為上和__cdecl有乙個共同點:實參和形引數目不符不會導致堆疊錯誤。
不過,即使用暫存器傳遞引數,編譯器在進入函式時,還是會將暫存器裡的引數存入堆疊指定位置。引數和區域性變數一樣應該在堆疊中有一席之地。引數可以被理解為由呼叫函式指定初值的區域性變數。
函式呼叫約定和堆疊
編譯器一般使用堆疊實現函式呼叫。堆疊是儲存器的乙個區域,嵌入式環境有時需要程式設計師自己定義乙個陣列作為堆疊。windows為每個執行緒自動維護乙個堆疊,堆疊的大小可以設定。編譯器使用堆疊來堆放每個函式的引數 區域性變數等資訊。函式呼叫經常是巢狀的,在同一時刻,堆疊中會有多個函式的資訊,每個函式占用...
函式呼叫約定和堆疊
編譯器一般使用堆疊實現函式呼叫。堆疊是儲存器的乙個區域,嵌入式環境有時需要程式設計師自己定義乙個陣列作為堆疊。windows為每個執行緒自動維護乙個堆疊,堆疊的大小可以設定。編譯器使用堆疊來堆放每個函式的引數 區域性變數等資訊。函式呼叫經常是巢狀的,在同一時刻,堆疊中會有多個函式的資訊,每個函式占用...
函式呼叫約定和堆疊
編譯器一般使用堆疊實現函式呼叫。堆疊是儲存器的乙個區域,嵌入式環境有時需要程式設計師自己定義乙個陣列作為堆疊。windows為每個執行緒自動維護乙個堆疊,堆疊的大小可以設定。編譯器使用堆疊來堆放每個函式的引數 區域性變數等資訊。函式呼叫經常是巢狀的,在同一時刻,堆疊中會有多個函式的資訊,每個函式占用...