2012-05-18 31 views
15

我想寫一個返回類型爲va_list的函數。在C中返回va_list安全嗎?

例如:va_list MyFunc(va_list args);

這是安全和便攜式?

+4

如果你的意圖是傳入'va_list',修改它,然後在函數返回時使用修改過的'va_list',最好考慮將指向'va_list'的指針傳遞給'MyFunct() '並通過指針使其在列表上起作用。該標準特別提到腳註允許使用該技術。 –

+0

這正是我的意圖。你能指出標準的地方嗎? –

+2

在我看來,'va_list'是一個壞主意。通常有更好的解決方案更安全。所以我會認真思考,併爲該功能的設計和實現提供更好的解決方案。 –

回答

6

va_list可能(但不能保證)是一個數組類型,所以您無法按值傳遞或返回它。看起來好像它的代碼可能只是傳遞/返回指向第一個元素的指針,所以您可以在被調用者中使用該參數,但是您可能會在原始代碼上執行該操作。

形式上你可以說va_list是一個實體類型,而不是一個值類型。您將其複製爲va_copy,而不是通過賦值或通過函數參數/返回。

1

雖然你絕對可以return這樣一個值,我不知道是否可以用有用的方式使用返回值。

由於va_list S上的處理需要特殊處理(va_start()va_copy()後需要va_end()),以及va_start/copyva_end宏甚至允許包含{ }執行這一配對,你不能說一個沒有其他。

+3

'va_copy'用於創建* second *'va_list'對象,該對象可以獨立於原始對象進行讀取。由於這不是這種情況,所以我會說可以傳遞並返回'va_list'對象。此外,該標準沒有提到'va_start()'和'va_end()'必須在同一個範圍內,因此我不知道它們如何被允許包含'{':es。 – Lindydancer

+2

@Lindydancer哦,不知道。 [Here](http://linux.die.net/man/3/va_start)我讀到「每次調用va_start()都必須匹配va_end()在相同函數中的相應調用」和「每次調用va_copy()必須在相同的函數中匹配va_end()的相應調用。「,所以我認爲它是從標準錐... – glglgl

+0

@glglgl:」在同一個函數中「並不一定意味着」在同樣的範圍「,所以並不意味着宏可以使用不匹配的大括號。但它確實允許'va_copy'使用像'alloca'這樣的技巧,因爲新列表不會超出函數返回的範圍。 –

1

無論語言標準如何,這在實踐中都不太可能發揮作用。 A va_list很可能是指向由呼叫者放置在堆棧上的呼叫記錄的指針,以便爲被呼叫者帶來利益。一旦被調用者返回,堆棧中的內存是公平的遊戲以供重用。

返回類型va_list不太可能實際上將列表內容複製回調用者。儘管這將是C的有效實現,但如果標準要求這樣做,那麼這將成爲規範中的缺陷。

+0

「va_end」宏存在的原因正是因爲'va_list'不一定只是指向堆棧上的某個指針。否則,'va_end'將永遠是空操作。存在'va_list'對象在堆上分配的實現。 –

+0

@DietrichEpp好信息,我以爲'va_end'有一些註冊窗口或舊的實現,只允許一次迭代器。調整了我的答案,但這只是一個相對重點問題......大多數架構不會使用可變參數堆。 – Potatoswatter

0

傳遞指向另一個函數的指針與返回該指針的 完全不同。許多/大多數實現將 實際變量參數存儲在棧幀中,該棧幀在可變參數函數返回時被破壞。 (即返回一個va_list或一個指向 的指針,會給你指向局部變量的指針,這些指針被破壞) 。 - 第

在我的情況

好,我會爲警告返回的va_list回來,但感謝 - Hayri維吾爾族如果你傳遞一個指向va_list的功能MyFunc(va_list *args) Koltuk

,你不需要將修改後的(由va_arg(*args, type))參數列表傳回,因爲MyFunc修改了原始列表。

+0

我不認爲它是指定'MyFunc'是否修改原始列表。我當然遇到了兩種工作方式的實現。 – supercat

+0

@supercat - 如果指向任何對象的指針被傳遞給函數,並且該函數修改指向的對象,則固有原始對象被修改。 – Armali

+0

如果一個va_list是一個簡單的指針(在許多平臺上最爲有效),將它傳遞給一個函數會給函數一個指針的副本,並且va_arg會增加指針的副本而不會影響原始指針。 – supercat