2011-10-03 31 views
7

關於gnu's C的文檔指出如果函數具有__attribute__((sentinel))它必須具有NULL作爲該函數的最後一個參數。如何使用自定義標記值創建可變參數函數?

是否可以有任何其他值作爲結束參數列表的標記?

+1

至於創建這樣的功能,顯然你可以做到這一點。我不知道任何GNU擴展,以檢查任意可變參數方案的參數是否正確。他們甚至沒有一個屬性可以將參數標記爲給出了多少個參數的「計數」,以便編譯器可以檢查它們是否正確。 –

回答

3

如果您足夠了解它,可以使用任何想要標記參數列表末尾的值來從參數列表中抓取它。不過,編譯器通常不會檢查您選擇的值是否在調用函數時實際傳遞,因此您需要小心。

本質上你只是以通常的方式創建一個可變參數函數,而當你閱讀一個與你的哨兵匹配的函數時,你停止閱讀參數的函數 - 沒有什麼特別的要做,但你需要知道什麼類型的參數來閱讀。

例如:

#include <stdarg.h> 

/* Count arguments up to the number 5 */ 
int countArgsTilFive(int first, ...) 
{ 
    int res = 1; 
    va_list ap; 
    if (first == 5) return 0; 
    va_start(ap,first); 
    while (va_arg(ap,int) != 5) res++; 
    va_end(ap); 
    return res; 
} 

...將計算其所有5之前發生爭論。如果你不通過5列表中的某處,或者你傳遞的參數不是int,那麼可能會發生壞事。

與指針,其中前哨淋巴結作爲第一過去了,再次作爲最後一個參數又如:

/* Count arguments, excluding the first, until the first occurs again */ 
int countPtrs(void *sentinel, ...) 
{ 
    int res = 0; 
    va_list ap; 
    va_start(ap,sentinel); 
    while (va_arg(ap,void *) != sentinel) res++; 
    va_end(ap); 
    return res; 
} 
+1

使用GCC的'__attribute __((sentinel))'編譯器_can_檢查參數列表是否以給定的值結束。只是它允許的唯一值是'NULL' - 它不會讓您爲編譯器選擇另一個值來驗證。 –

+1

如果他只是想知道是否有像__attribute __((sentinel))這樣的任意哨兵值,那麼答案就沒有那麼有用了,但是如果關於__attribute __((sentinel))的東西留下了印象非空哨兵根本無法使用,它應該清除它。 – Dmitri

0

這是(經過編輯下來的版本)蘋果如何定義得心應手NS_REQUIRES_NIL_TERMINATION預編譯檢查,即需要一些方法的零定點...

+ (NSArray*)arrayWithRects:(NSR)rect,...NS_REQUIRES_NIL_TERMINATION;

#if !defined(NS_REQUIRES_NIL_TERMINATION) 
#if defined(__APPLE_CC__) && (__APPLE_CC__ >= 5549) 
    #define NS_REQUIRES_NIL_TERMINATION __attribute__((sentinel(0,1))) 
#else 
    #define NS_REQUIRES_NIL_TERMINATION __attribute__((sentinel)) 
#endif 
#endif 

不太清楚的differenc e是在這兩個編譯器指令之間..但我認爲這個結構可以與「其他」,「定製」哨兵一起使用..我在想NSNotFound - XX_REQUIRES_NSNOTFOUND_TERMINATION或類似的東西?

相關問題