如何使用自定义标记值创建可变参数函数?

时间:2011-10-03 17:15:42

标签: c variadic-functions sentinel

关于gnu的C的文档说明如果函数有__attribute__((sentinel)),它必须有NULL作为函数的最后一个参数。

是否可以将任何其他值作为结束参数列表的标记?

2 个答案:

答案 0 :(得分:4)

你可以使用你想要标记参数列表末尾的任何值,前提是你已经足够了解它从参数列表中获取它。但是,在调用函数时,编译器通常不会检查您选择的值是否实际传递,因此您需要注意它。

基本上你只是以通常的方式创建一个可变参数函数,并且当你读取一个与你的哨兵相匹配的参数时你会停止读取参数 - 没有什么特别的要做,但是你需要知道什么类型的参数阅读。

例如:

#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,则可能会发生错误。

另一个带指针的例子,其中一个sentinel节点作为第一个传递,另一个作为最后一个参数传递:

/* 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 :(得分:0)

这是(一个经过编辑的版本)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 - {{1}或类似的东西?