How to create a variable function with a custom sentinel value?

The gnu C documentation says that if a function has __attribute__((sentinel)) , it should have NULL as the last argument to the function.

Is it possible to have any other value as a marker to complete the argument list?

+7
source share
2 answers

You can use any value that you want to mark at the end of the argument list, provided that you know enough about it in the argument list. The compiler usually does not verify that the value you select is actually passed when the function is called, so you need to take care of this.

Basically, you simply create a variable function in the usual way, and inside the function you stop reading the arguments when you read the one that matches your sentinel - there is nothing special to do, 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 can happen if you don't pass it 5 somewhere in the list, or pass arguments that are not int .

Another example with pointers, where the guard symbol 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; } 
+3
source

This is an (edited version) how Apple defines a convenient NS_REQUIRES_NIL_TERMINATION , i.e. require a zero gatekeeper 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 these two compiler directives .. but I assume that this construct can be used with "other", "regular" sentries .. I think NSNotFound is XX_REQUIRES_NSNOTFOUND_TERMINATION or something similar to this?

0
source

All Articles