[英]How to determine the end of va_arg list?
我有一個 function foo(char *n, ...);
我需要獲取並使用所有可選的char
參數。 我有一個想法使用
while(va_arg(argPtr, char) != NULL)
{
...
}
了解我何時到達列表末尾。 那么,它會工作嗎,如果在 function 電話中我會做foo(n, 't', 'm', '$', NULL);
?
NULL
會被 va_arg 讀取為 char 嗎? 或者也許有一種更常見的方法來確定列表的結尾,而不添加NULL
作為最后一個參數?
對於使用va_arg
來確定給定調用傳遞的參數的數量或類型的函數,沒有直接的方法。
特別是您提出的方法:
while(va_arg(argPtr, char) != NULL)
不正確。 va_arg(argPtr, char)
產生一個char
類型的值,而NULL
是一個空指針常量。 ( NULL
通常定義為0
,它相當於空字符'\\0'
,但你不能依賴它。)
任何可變參數函數都必須有一種方法供調用者指定參數的數量和類型。 例如, *printf
函數通過(非可變參數)格式字符串執行此操作。 POSIX execl*()
函數需要一系列char*
參數; 參數列表的末尾由調用者用(char*)NULL
標記。 其他方法也是可能的,但它們幾乎都依賴於運行時參數中給出的信息。 (您可以使用其他方法,例如全局變量。請不要。)
這給調用者帶來了負擔,以確保傳遞給函數的參數是一致的。 函數本身無法確認這一點。 不正確的調用,如printf("%d\\n", "hello")
或execlp("name", "arg1")
具有未定義的行為。
還有一件事:您不能將va_arg
與char
類型的參數一起使用。 當您調用可變參數函數時,對應於, ...
參數會被提升。 類型比int
窄的整數參數被提升為int
或unsigned int
,而float
類型的參數被提升為double
。 如果調用者傳遞char
類型的參數,則該函數必須調用va_arg(argPtr, int)
。
(在您不太可能遇到的非常模糊的情況下, char
可以提升為unsigned int
。只有當普通char
是 unsigned 並且sizeof (int) == 1
才會發生這種情況,這意味着一個字節至少為 16位。)
在這一點上只是晚了幾年,但我有一些有趣的貢獻。 在這種情況下,我會使用預處理器。 順便說一下,警告變量類型不正確。
注意:用括號括起 function 名稱將使宏忽略它,同時允許文件符號與 API 相同(宏用法除外)。
像這樣掩蓋你的功能:
#define my_func(...) my_func(__VA_ARGS__, NULL);
void (my_func)(...)
{
/* ... */
}
將可變參數轉換為int[]
,以靜態確定所述數組的sizeof
:
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
#define NARGS(...) ARRAY_LENGTH((int[])({ __VA_ARGS__ }))
類似mask,只是在前面加一個count參數:
#define my_func(...) my_func(NARGS(__VA_ARGS__), __VA_ARGS__);
void (my_func)(int n, ...)
{
/* ... */
}
在問題的 scope 之外,但由於我在滾動。
我總是使用 GCC,有時使用以下。 我相信 Clang 中有半兼容功能,但我不確定。 這使您可以確保傳遞的是實際數組而不是指針。
#define TYPE_COMPATABLE(x, y) __builtin_types_compatible_p(__typeof__(x), __typeof__(y))
#define CHOOSE_EXPR(b, x, y) __builtin_choose_expr((b), (x), (y))
#define IS_ARRAY(a) (!TYPE_COMPATABLE((a), &(a)[0]))
#define ARRAY_LENGTH(a) \
({ \
_Static_assert(IS_ARRAY(a), "non-array"); \
sizeof(a) / sizeof((a)[0]); \
})
#define NARGS(...) ARRAY_LENGTH((int[])({ __VA_ARGS__ }))
到時候,可能就用 C++ 呵呵。
基本的想法是可行的。 但是您以幾乎肯定不會的方式填寫了詳細信息。
當您使用可變參數時,通常的隱式轉換規則不適用。 相反,會發生默認參數提升,這意味着任何小於int
/ unsigned int
整數類型都會被轉換為其中之一——這不是唯一的提升,而是這里唯一相關的——這也意味着沒有自動轉換為您使用va_arg
指定的任何類型。
這意味着:
va_arg(..., char)
,因為不可能將char
作為可變參數函數參數傳遞。NULL
作為可變參數函數參數傳遞,因為它的具體類型在很大程度上依賴於實現。 現實類型是int
、 long
、 void *
,還有許多其他不太現實但同樣有效的類型。你可以改變
while(va_arg(argPtr, char) != NULL)
到
while(va_arg(argPtr, int) != 0)
和電話
foo(n, 't', 'm', '$', NULL);
到
foo(n, 't', 'm', '$', 0);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.