2011-10-03 17 views
7

La documentación en C de gnu indica que si la función tiene __attribute__((sentinel)) debe tener NULL como último argumento para la función.¿Cómo crear una función variadica con un valor centinela personalizado?

¿Es posible tener cualquier otro valor como marcador para finalizar la lista de argumentos?

+1

En cuanto a la creación de dicha función, claramente usted puede hacerlo. No sé de ninguna extensión de GNU para verificar que los argumentos sean correctos para los esquemas varargs arbitrarios. Ni siquiera tienen un atributo para marcar un parámetro como un "recuento" de cuántos argumentos se dieron para que el compilador pueda verificar si lo hicieron bien. –

Respuesta

3

Puede usar cualquier valor que desee para marcar el final de la lista de argumentos, siempre que sepa lo suficiente sobre ello desde la lista de argumentos. El compilador normalmente no verificará que el valor que elija en realidad se pase cuando se llama a la función, por lo que deberá tener cuidado con ello.

Esencialmente usted acaba de crear una función variable de la manera habitual, y dentro de la función deja de leer los argumentos cuando lee uno que coincida con su centinela - no hay nada particularmente especial que hacer, pero necesita saber qué tipos de argumentos para leer.

Por ejemplo:

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

... contará todos sus argumentos que se producen antes 5. Sin embargo, pueden pasar cosas malas si no lo pasa 5 en algún lugar de la lista, o si le pasa argumentos que no son int.

Otro ejemplo con punteros, donde un ganglio centinela se pasa como la primera, y de nuevo como el último, el argumento:

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

Con '__attribute__ ((sentinel)) de GCC' 'el compilador _ puede_ comprobar que la lista de argumentos finaliza con el valor dado. Es solo que el único valor que permite es 'NULL' - no le permite elegir otro valor para que el compilador lo verifique. –

+1

Si solo quiere saber si hay algo como '__attribute __ ((sentinel))' para valores centinela arbitrarios, entonces la respuesta no es tan útil ... pero si las cosas sobre '__attribute __ ((sentinel))' dejaron la impresión que los centinelas que no son NULL no podrían usarse en absoluto, debería aclararlo. – Dmitri

0

Esta es (una versión editada abajo de) cómo Apple define la práctica NS_REQUIRES_NIL_TERMINATION comprobación previa a la compilación, es decir, que requiere un centinela nula con algún método ...

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

No estoy seguro de lo que el differenc e está entre esas dos directivas de compilación ... pero supongo que esta construcción podría usarse con "otros" centinelas "personalizados". Estoy pensando en NSNotFound - XX_REQUIRES_NSNOTFOUND_TERMINATION o algo así.

Cuestiones relacionadas