簡體   English   中英

多個va_end調用的順序是否重要?

[英]Does the ordering of multiple va_end calls matter?

我有以下代碼:

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_start調用va_end

我不確定的是,電話的順序是否重要。 特別是

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

與...完全相同

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

在上面的示例代碼中?

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>頭。 你不應該擔心他們。

只需為每個va_start調用一次va_end,但是您需要使用va_arg來獲取各個參數。 這是一個例子: http//www.cplusplus.com/reference/cstdarg/va_start/

另外,我認為訂單不重要。

一些 [舊]實現中, va_start擴展為左括號{后跟一些聲明, va_end擴展為右括號}可能先於一些“終結”。 在道德上,他們應該匹配。 在實踐中,通常但並非總是如此,順序並不重要(但原則上它確實很重要)。

在最近的GCC中,這些va_startva_end宏擴展為__builtin_va_start__builtin_va_end調用,因此編譯器可能會關心(可能在將來某個版本中)這些是正確嵌套的。 看到這個 所以“好”的順序應該是:

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_startva_end是“嵌套”

當然,你需要調用va_arg來真正檢索可變參數(我希望你的process正在這樣做)。 stdarg(3)解釋得很好(對於C代碼):

每次調用va_start()必須與同一函數中相應va_end()調用相匹配。

注意相應的單詞(重點是我的)。 我認為這意味着va_startva_end確實是嵌套的 (至少在原理上)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM