gnu的C语言文档说明,如果函数具有__attribute__((sentinel))
,则必须将NULL
作为函数的最后一个参数。
是否可以有任何其他值作为结束参数列表的标记?
您可以使用任何值来标记参数列表的结束,只要您对它有足够的了解,就可以从参数列表中获取它。当函数被调用时,编译器通常不会检查你选择的值是否被传递,所以你需要小心处理。
本质上,你只是以通常的方式创建一个可变函数,在函数内部,当你读到一个与你的哨兵匹配的参数时,你就停止读取参数——没有什么特别要做的,但是你需要知道要读取什么类型的参数。
例如:#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;
}
这是Apple如何定义方便的NS_REQUIRES_NIL_TERMINATION
预编译检查的(编辑后的版本),即要求用某些方法设置nil哨兵…
+ (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
不太确定这两个编译器指令之间的区别是什么…但我认为这个结构可以与"其他"、"自定义"哨兵一起使用。我想NSNotFound
- XX_REQUIRES_NSNOTFOUND_TERMINATION
或类似的东西?