回覆列表
-
1 # IT劉小虎
-
2 # 周林ZhouLin
看了底下兄弟的答覆,只能說答對了一半。
真正的原因在於ABI(應用程式二進位制介面)。
ABI定義了與系統互動的細節:如資料型別、大小和對齊;呼叫約定(控制函式的引數的傳遞方向、可變長度處理、堆疊清理主體以及如何接受返回值等);系統呼叫的編碼和一個應用如何向作業系統進行系統呼叫;以及在一個完整的作業系統ABI中,目標檔案的二進位制格式、程式庫等等。一個完整的ABI,像Intel二進位制相容標準 (iBCS),允許支援它的作業系統上的程式不經修改在其他支援此ABI的操作體統上執行。
其他的 ABI 標準化細節還包括 C++ 名稱修飾 ,和同一個平臺上的編譯器之間的呼叫約定,但是不包括跨平臺的相容性。
至於底下兄弟所說的EAX儲存返回值,這個只是X86的ABI規範,在PowerPC等其他CPU架構平臺,實現是不一樣的!——PowerPC下,返回值是儲存在R3暫存器中的
-
3 # 壹仁說
在C語言中,區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體就會被釋放。如果函式只是返回區域性變數,那麼這個區域性變數會被複制一份傳回被呼叫處。但是如果函式返回的是區域性變數的地址,那麼就會報錯,因為函式只是把指標複製後返回了,但是指標指向的內容已經被釋放,這樣指標指向的內容就是不可預料的內容,程式就會出錯。準確的來說,函式不能透過返回指向棧記憶體的指標(返回指向堆記憶體的指標是可以的)。
C語言函式的區域性變數在函式執行完畢後,會被釋放,相信即使是C語言初學者,也是瞭解這一點的。不過,我們在函式中定義一個區域性變數,卻是可以透過 return 語法將其返回給呼叫者的,這也許就是題主的疑惑之處。
C語言函式怎麼可以把一個被釋放的值返回給呼叫者使用呢?
請看下面這張圖,進一步來說,C語言程式每呼叫一個函式,就會在棧區為其分配一塊區域,所有區域性變數都是在這塊區域裡存放的,函式執行完畢返回後,系統自動就將這塊區域收回了。
這塊區域較為正式的名字叫“棧幀”。
既然函式的區域性變數都存放在棧區,棧區在函式返回就釋放了,那為什麼 add 函式還能把區域性變數返回呢?
其實函式返回的並不是區域性變數,而是區域性變數裡面存放的資料
我們用鞋櫃來比喻區域性變數,用鞋子來比喻資料。我們想取出的是鞋子,而不是鞋櫃,對嗎?
以我的機器為例,在函式執行完畢後,系統會先將返回值暫存在暫存器 eax 裡,所以即使函式的棧幀被系統收回了,它的返回值依然在 eax 裡儲存的很好。函式返回後,系統再把返回值從 eax 中取出,賦值給呼叫者。請看下面這個例子:
我們檢視它的彙編程式碼,發現一切和我們預料的一致:
從彙編程式碼可以看出,C語言的 return 實際上返回的是是將區域性變數裡的值,而不是直接返回區域性變數。
不過,因為返回值是存放在區域性變數裡的,而區域性變數被釋放了,所以必須再為該值找一個“容器”,該“容器”在本例中就是 eax 暫存器。
總結一下
題目所說的“C語言函式返回區域性變數”這一過程是這樣的:在區域性變數被釋放之前,C語言程式將存放在其中的值暫時存放到 eax 暫存器中,eax 是不會被釋放的,所以函式執行完畢後,return 仍然能將其中的值返回給呼叫者。