有什麼辦法可以計算長度爲va_list
?所有的例子我都看到了變量參數的數量。使用變量列表參數時va_list的長度?
回答
有沒有辦法計算一個va_list
的長度,這就是爲什麼你需要類似於函數printf
中的格式字符串。
唯一
功能,可與工作
宏的va_list
are:
va_start
- 開始使用va_list
va_arg
- 獲得一個參數va_end
- 停止使用va_list
va_copy
(因爲C++ 11和C99) - 複製va_list
請注意,你需要調用va_start
和va_end
在同一範圍內,這意味着你不能在其析構函數調用在其構造va_start
和va_end
一個工具類,把它包裝(我被這一朝被蛇咬)。
例如這個類是毫無價值:
class arg_list {
va_list vl;
public:
arg_list(const int& n) { va_start(vl, n); }
~arg_list() { va_end(vl); }
int arg() {
return static_cast<int>(va_arg(vl, int);
}
};
GCC輸出following error
t.cpp: In constructor
arg_list::arg_list(const int&)
:
Line 7: error:va_start
used in function with fixed args
compilation terminated due to -Wfatal-errors.
有一個可變參數函數來確定很多參數是如何傳遞沒有直接方式。 (至少沒有便攜的方式; <stdarg.h>
接口不提供該信息。)
有幾種間接方式。
兩個最常見的有:
- 格式字符串(指定,通過你可以稱之爲一個小的簡單的語言,其餘參數的數量和類型)。
*printf()
和*scanf()
函數族使用這種機制。 - 表示參數結束的標記值。一些Unix/POSIX
exec*()
功能家族這樣做,使用空指針來標記參數的結尾。
但也有其他可能性:
- 更簡單地說,一個整數計數,指定以下參數的數量;大概在這種情況下,他們都是同一類型的。
- 交替參數,其中參數可以是指定以下參數類型的枚舉值。一個假設的例子可能看起來像:
func(ARG_INT, 42, ARG_STRING, "foo", ARG_DOUBLE, 1.25, ARG_END);
甚至:
func("-i", 42, "-s", "foo", "-d", 1.25, "");
如果你想效仿參數通常傳遞給Unix命令的方式。
你甚至可以分配一個值到全局變量指定的參數個數:
func_arg_count = 3;
func(1, 2, 3);
這將是醜陋的,但完全合法的。
在所有這些技術中,傳遞一致參數完全是調用者的責任;被調用者只能使用假設其參數是正確的。
請注意,可變參數函數不需要處理傳遞給它的所有參數。例如,這樣的:
printf("%d\n", 10, 20);
將打印10
,靜靜地忽略20
。很少有任何理由利用該功能。
尚未提及的一種方法是使用預處理器宏使用va_list長度作爲第一個參數調用variadict函數,並且還沿參數向前。這有點「可愛」的解決方案,但不需要手動輸入參數列表長度。
假設你有以下功能:
int Min(int count, ...) {
va_list args;
va_start(args, count);
int min = va_arg(args, int);
for (int i = 0; i < count-1; ++i) {
int next = va_arg(args, int);
min = min < next ? min : next;
}
va_end(args);
return min;
}
的想法是,你必須能夠通過使用一個掩碼__VA_ARGS__
計算的參數個數的預處理宏。有確定__VA_ARGS__
長度包括P99和Boost預處理器幾個不錯的預處理程序庫,但只是讓我不要在這個答案留孔,下面是它可以做到:
#define IS_MSVC _MSC_VER && !__INTEL_COMPILER
/**
* Define the macros to determine variadic argument lengths up to 20 arguments. The MSVC
* preprocessor handles variadic arguments a bit differently than the GNU preprocessor,
* so we account for that here.
*/
#if IS_MSVC
#define MSVC_HACK(FUNC, ARGS) FUNC ARGS
#define APPLY(FUNC, ...) MSVC_HACK(FUNC, (__VA_ARGS__))
#define VA_LENGTH(...) APPLY(VA_LENGTH_, 0, ## __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#else
#define VA_LENGTH(...) VA_LENGTH_(0, ## __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#endif
/**
* Strip the processed arguments to a length variable.
*/
#define VA_LENGTH_(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...) N
注意:一上面的很多噪音都是針對MSVC的解決方案。
利用上述所定義,可以創建單個宏來執行所有基於長度的操作:
/**
* Use the VA_LENGTH macro to determine the length of the variadict args to
* pass in as the first parameter, and forward along the arguments after that.
*/
#define ExecVF(Func, ...) Func(VA_LENGTH(__VA_ARGS__), __VA_ARGS__)
該宏能夠調用任何variadict函數,只要它始於int count
參數。總之,而不是使用:
int result = Min(5, 1, 2, 3, 4, 5);
您可以使用:
int result = ExecVF(Min, 1, 2, 3, 4, 5);
這裏的閩的模板版本,它使用相同的方法:https://gist.github.com/mbolt35/4e60da5aaec94dcd39ca
你可以嘗試,如果使用功能_vscprintf
你在MS Visual Studio下工作。 這裏是一個如何使用_vscprintf的例子,我用它來知道我的控制檯標題需要多少空間到malloc。
int SetTitle(const char *format,...){
char *string;
va_list arguments;
va_start(arguments,format);
string=(char *)malloc(sizeof(char)*(_vscprintf(format,arguments)+1));
if(string==NULL)
SetConsoleTitle("Untitled");
else
vsprintf(string,format,arguments);
va_end(arguments);
if(string==NULL)
return SETTITLE_MALLOCFAILED;
SetConsoleTitle(string);
free(string);
return 0;
}
或者你也可以做到這一點,添加輸出到臨時文件,然後從中讀取數據到分配的內存就像我在接下來的例子中那樣:
void r_text(const char *format, ...){
FILE *tmp = tmpfile();
va_list vl;
int len;
char *str;
va_start(vl, format);
len = vfprintf(tmp, format, vl);
va_end(vl);
rewind(tmp);
str = (char *) malloc(sizeof(char) * len +1);
fgets(str, len+1, tmp);
printf("%s",str);
free(str);
fclose(tmp);
}
使用_vscprintf確定變量列表的長度。 https://msdn.microsoft.com/en-us/library/w05tbk72.aspx
- 1. 使用va_list打印參數列表
- 2. 傳遞變量的可變長度的參數列表在PHP
- 3. Codeigniter可變長度參數列表
- 4. 可變長度模板參數列表?
- 5. 傳遞數組變量長度參數列表
- 6. 禁用Rubocop參數列表長度
- 7. vsprintf_s()va_list的時候已經長由局部變量
- 8. Erlang函數參數列表的可變長度
- 9. 使用變量設置數組長度
- 10. 將變量長度列表作爲參數傳遞給線程函數
- 11. 可變長度參數
- 12. PHP - 傳遞數組作爲可變長度參數列表
- 13. 功能的可變長度參數列表
- 14. 雙變量參數列表
- 15. WCF/Rest/UriTemplate可變長度查詢字符串參數列表?
- 16. 使用變量模板解包參數列表時獲取參數索引
- 17. 解析R中的變量列長度
- 18. 將函數應用於任意長度的參數列表
- 19. awk錯誤參數列表太長,只有兩個變量
- 20. 可變參數(參數va_list的va_start)不與通按引用參數工作
- 21. 功能的可變長度的參數
- 22. C++/CLI中的變量參數列表
- 23. Renderscript中的變量參數列表
- 24. WSDL中的變量參數列表
- 25. 帶有函數回調的變量數量(va_list)?
- 26. 使用可變長度的未命名的參數命名參數在Python
- 27. 可變長度的空閒列表
- 28. UNIX中變量的長度
- 29. 檢查變量的長度
- 30. 命名變量的長度
我看到的'va_arg'的每個實現只是移動指針'sizeof(arg_type)'個字節,所以無法知道長度;那是你的工作。 – 2013-09-03 05:22:17