[英]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_start
和va_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_start
和va_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_start
和va_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_start
& va_end
是“嵌套”
當然,你需要調用va_arg
來真正檢索可變參數(我希望你的process
正在這樣做)。 stdarg(3)解釋得很好(對於C代碼):
每次調用
va_start()
必須與同一函數中相應的va_end()
調用相匹配。
注意相應的單詞(重點是我的)。 我認為這意味着va_start
和va_end
確實是嵌套的 (至少在原理上)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.