2010-04-29 85 views
11

前幾天我參加了一次技術性採訪,有人問我 C編譯器如何通過可變數量的參數實現函數? 它如何通過堆棧?C編譯器如何使用可變數量的參數實現函數?

有沒有人知道或可以表明這一點?

感謝, 丹

+1

據我所知,可變參數函數是依賴於實現的。 – WhirlWind 2010-04-29 17:43:00

回答

10

據我所知,用C ...

  • 的調用函數參數推到堆棧中從右到左的順序。

  • 調用者負責在調用函數執行後從堆棧中移除參數。這可能正是因爲調用者保證知道它放在堆棧上的參數有多少,而被調用的函數可能會錯誤。


P.S:調用約定通常是實現特定的。我剛剛描述的被稱爲「cdecl」調用約定。將其與通常稱爲「stdcall」的調用約定相比較,其中被調用函數負責從堆棧中移除其參數。因此,它不支持可變長度參數列表。


P.P.S:作爲用戶nategoose評論,我沒有提到的說法如何變量列表實際上使用。見例如POSIX documentation for the <stdarg.h> header瞭解更多信息。

+2

這很清楚,但你忽略了被調用者的角色。被調用者(如printf)必須使用一個或多個強制參數(如格式字符串)來了解堆棧中的參數應該是什麼。然後它使用目標特定的宏以數組的形式訪問這些宏(系統棧是一個可以移動其頭部的數組)。 stdarg.h頭文件包含您需要執行此操作的宏,並且通常通常將一個指向此數組的頭的指針傳遞給一個函數,該函數將在該函數上工作(如vprintf)。 – nategoose 2010-04-29 18:50:52

+0

@nategoose:謝謝你的寶貴補充。只是爲了讓你知道,我最初故意拋開了這個,因爲OP詢問*編譯器*如何實現可變參數列表,而不是*程序員實際如何使用它們。我已經添加了一個超鏈接到現在的參考文檔。 – stakx 2010-04-29 21:02:14

7

它使用va_宏實現它們 - 例如va_start。這些宏做的是實現定義 - 換句話說,它會因CPU體系結構和體系結構以及編譯器和編譯器而異。但他們必須玩C調用堆棧。通常,這將涉及以最後一個命名參數的地址爲基礎,然後通過在此基礎上執行指針運算來訪問可變參數。

+0

是的,我記得這就是爲什麼你總是需要一個命名參數之前...... – dicroce 2010-04-29 18:01:17

-1

調查va_start,va_arg和va_end。 Here是這方面的一大堆信息。

0

至於,你傷心,你有在高科技採訪這個問題,我會認爲正確的答案應該是:

來電將推明確的參數堆棧,變量參數和變量參數的數量本身。然後,目標函數代碼將負責根據傳遞的計數及其堆棧地址彈出所有參數。

並添加一些想法,爲什麼將此參數放在單獨的數組中不方便。

相關問題