2011-10-03 11 views
7

La documentazione su gnu's C indica che se la funzione ha __attribute__((sentinel)) deve avere NULL come ultimo argomento della funzione.Come creare una funzione variadica con valore sentinella personalizzato?

È possibile avere qualsiasi altro valore come indicatore per terminare la lista degli argomenti?

+1

Per quanto riguarda la creazione di tale funzione, è chiaramente possibile farlo. Non conosco alcuna estensione GNU per verificare che gli argomenti siano corretti per gli schemi arbitrari di vararg. Non hanno nemmeno un attributo per contrassegnare un parametro come un "conteggio" di quanti argomenti sono stati dati in modo che il compilatore possa verificare se è stato corretto. –

risposta

3

È possibile utilizzare qualsiasi valore che si desidera contrassegnare la fine dell'elenco di argomenti, purché ne si sappia abbastanza sull'argomento dalla lista degli argomenti. Il compilatore normalmente non controlla che il valore scelto venga effettivamente passato quando viene chiamata la funzione, quindi è necessario averne cura.

Fondamentalmente si crea una funzione variadica nel solito modo, e all'interno della funzione si interrompe la lettura degli argomenti quando si legge uno che corrisponde alla sentinella - non c'è niente di particolarmente speciale da fare, ma è necessario sapere quali tipi di argomenti da leggere.

Ad esempio:

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

... conterà tutti i suoi argomenti che si verificano prima 5. Le cose brutte potrebbero accadere se non lo passi a un numero 5 da qualche parte nella lista, comunque, o se gli passi argomenti che non sono int.

Un altro esempio con i puntatori, in cui un linfonodo sentinella viene passato come il primo, e ancora una volta come ultimo argomento:

/* 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 __ ((sentinella)) di GCC' il compilatore _can_ controlla che la lista di argomenti finisca con il valore dato. È solo che l'unico valore consentito è 'NULL' - non ti consente di scegliere un altro valore da verificare per il compilatore. –

+1

Se vuole solo sapere se c'è qualcosa come "__attribute __ ((sentinel))" per valori arbitrari sentinella, allora la risposta non è così utile .. ma se le cose su "__attribute __ ((sentinel))" hanno lasciato l'impressione che le sentinelle non NULL non potevano essere usate affatto, dovrebbe chiarirlo. – Dmitri

0

Questo è (una versione modificata-down) come Apple definisce la portata di mano NS_REQUIRES_NIL_TERMINATION controllo pre-compilazione, vale a dire da richiedere una sentinella nil con qualche metodo ...

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

Non abbastanza sicuro di quello che il differenc e è tra queste due direttive del compilatore .. ma presumo che questo costrutto possa essere usato con sentinelle "altre", "personalizzate" .. Sto pensando NSNotFound - XX_REQUIRES_NSNOTFOUND_TERMINATION o qualcosa di simile a quello?

Problemi correlati