2011-10-03 60 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或类似的东西?

相关问题