2014-09-03 50 views
6

我有以下代碼:多個va_end調用的順序是否重要?

va_list va[2]; 
va_start(va[0], fmt); 
va_start(va[1], fmt); 
process(fmt, va); 
va_end(va[0]); 
va_end(va[1]); 

我看各個網站的文檔上va_startva_end,以及所有他們說的是,va_end應該調用每個va_start調用函數返回前。

我不確定的是電話的順序是否重要。具體地講,是

va_end(va[0]); 
va_end(va[1]); 

在上述示例代碼sementically相同

va_end(va[1]); 
va_end(va[0]); 

+1

您可能也有興趣'va_copy'。 – 2014-09-03 19:21:39

回答

1

一些 [舊]實施方式中,va_start擴展到左括號{其次是一些聲明,va_end擴展到右括號}可能通過一些「修訂」之前。道德上他們應該匹配。在實踐中,經常但不總是,秩序並不重要(但原則上它確實很重要)。

在最近的海灣合作委員會,這些va_startva_end宏擴展到__builtin_va_start & __builtin_va_end調用所以編譯器可能關心(也許在將來的某個版本),這些都是正確嵌套。見this。因此,「好」的順序應該是:

va_list va[2]; 
va_start(va[0], fmt); 
    va_start(va[1], fmt); 
    process(fmt, va); 
    va_end(va[1]); 
va_end(va[0]); 

在實踐中的va_end順序可能不管那麼多了。

縮進是我要強調的是,va_start & va_end是「築巢」

當然,你需要調用va_arg真正找回可變參數(我希望你process正在這樣做)。 stdarg(3)解釋以及(對於C代碼):

va_start()每次調用必須通過同樣的功能對應 調用va_end()一個匹配。

注意對應字(重點是我的)。我相信這意味着va_startva_end確實是嵌套(至少原則上)。

+0

IIRC,沒有執行的''''va_start'曾經那樣做過。一些(預標準)''實現了,但標準C和標準C++從未有''頭。 – hvd 2014-09-03 19:31:24

+0

同意。但是實現可能會做很奇怪的事情 – 2014-09-03 19:32:05

+0

除非任何一個標準需要特定的'va_end'調用順序,否則實現不能做出奇怪的事情。 – hvd 2014-09-03 19:32:43

3

與C99標準中唯一的相關要求是:

7.15.1變量參數列表訪問宏

1 [...]的va_startva_copy宏的每次調用應通過相同的函數調用va_end宏來匹配。

有多個va_end調用的順序以匹配的va_start,或到的那個的va_start反向匹配沒有要求,因此實現都必須接受任何順序。

你甚至可以使用烏七八糟像

void f(int a, ...) { 
    va_list ap; 
    goto b; 
a: 
    va_end(ap); 
    return; 
b: 
    va_start(ap, a); 
    goto a; 
} 

這符合本標準的所有要求,所以實現必須接受它。因此,不允許使用va_end擴展爲具有不匹配大括號的技巧。

實際上,我甚至都沒有意識到任何當前的實現,其中va_end都有任何必要的影響。我所能找到的所有實現,至多將值(或第一個子值,取決於類型)設置爲零,這將進一步使用va_arg失敗,但如果省略則不會導致問題va_end從您的代碼。大多數甚至沒有這樣做。現在,我不會真的從代碼中刪除它,因爲有一個合法的原因,爲什麼一個實現(當前或未來)可能會在其va_end中實際執行某些操作,但您可以假設當前和未來的實現至少會嘗試在一種符合標準要求的方式。

使用#define va_end(ap) }的歷史實現就是這樣:歷史。他們沒有在<stdarg.h>中提供該宏,他們甚至沒有<stdarg.h>標題。你不應該擔心他們。

+0

好的,但這只是答案的一半。很多實現都會執行不被「允許」執行的操作。這裏有嗎? – 2014-09-03 20:33:05

+0

@LightnessRacesinOrbit我知道一些C89之前的實現需要'va_start'和'va_end'來匹配'',但我沒有意識到任何實現''時都有任何問題。另外,一般來說,「標準說它沒問題」,如果備份,就足以作爲答案。當然,有些bug存在實現,如果有任何主流編譯器出現這些錯誤,在回答中提到它們是很好的,但是僅僅因爲假設的錯誤實現對標準說的內容有所缺點對我來說是新的。 – hvd 2014-09-03 20:42:58

+0

@LightnessRacesinOrbit實際上,我最近搜索了'va_end'完成*任何操作*的實現,如果'va_end'被省略,會導致問題,但我一直沒有找到任何示例。所以在實踐中,我認爲標準的要求比實際需要更嚴格。 – hvd 2014-09-03 20:44:52

相關問題