Question

The documentation on gnu's C states that if function has __attribute__((sentinel)) it must have NULL as a last argument to the function.

Is it possible to have any other value as marker for ending the argument list?

Was it helpful?

Solution

You can use whatever value you want to mark the end of the argument list, provided you know enough about it grab to it from the argument list. The compiler won't normally check that the value you choose is actually passed when the function is called, though, so you'll need take care with it.

Essentially you just create a variadic function in the usual way, and inside the function you stop reading arguments when you read one that matches your sentinel -- there's nothing particularly special to be done, but you need to know what types of arguments to read.

For example:

#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;
}

...will count all its arguments that occur before 5. Bad things could happen if you don't pass it a 5 somewhere in the list, though, or if you pass it arguments that aren't int.

Another example with pointers, where a sentinel node is passed as the first, and again as the last, argument:

/* 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;
}

OTHER TIPS

This is (an edited-down version of) how Apple defines the handy NS_REQUIRES_NIL_TERMINATION pre-compilation check, i.e. to require a nil sentinel with some method...

+ (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

Not quite sure what the difference is between those two compiler directives.. but I assume this construct could be used with "other", "custom" sentinels.. I'm thinking NSNotFound - XX_REQUIRES_NSNOTFOUND_TERMINATION or something akin to that?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top