L'unico requisito rilevante nello standard C99 è:
7.15.1 lista degli argomenti accesso variabili macro
1 [...] Ogni invocazione dei va_start
e va_copy
macro sarà abbinato da una corrispondente chiamata della macro va_end
nella stessa funzione.
Non v'è alcun obbligo per l'ordine di molteplici va_end
invocazioni a corrispondere a quella del va_start
, o per abbinare il contrario di quello di va_start
, così implementazioni sono tenuti ad accettare qualunque ordine.
Si potrebbe anche usare un orribile pasticcio come
void f(int a, ...) {
va_list ap;
goto b;
a:
va_end(ap);
return;
b:
va_start(ap, a);
goto a;
}
Questo corrisponde a tutti i requisiti della norma, in modo le implementazioni devono accettarlo. Di conseguenza, anche i punti in cui va_end
si espande a qualcosa con parentesi non corrispondenti non sono consentiti.
In pratica, non sono nemmeno a conoscenza di alcuna implementazione corrente in cui va_end
ha alcun effetto necessario. Tutte le implementazioni che sono stato in grado di trovare, al massimo impostano il valore (o il primo sotto-valore, a seconda del tipo) su zero, che farebbe un ulteriore uso di va_arg
fallire, ma non causerebbe problemi se si omette va_end
dal tuo codice. La maggior parte non lo fa nemmeno. Ora, in realtà non lo rimuoverò dal codice, poiché ci sono motivi legittimi per cui un'implementazione (attuale o futura) potrebbe effettivamente fare qualcosa nel suo va_end
, ma si può presumere che le implementazioni attuali e future tenteranno almeno di implementarla in un modo che corrisponda ai requisiti dello standard.
Le implementazioni storiche che utilizzano #define va_end(ap) }
sono proprio questo: cronologia. Non hanno fornito quella macro in <stdarg.h>
e non avevano nemmeno un'intestazione <stdarg.h>
. Non dovresti preoccuparti di loro.
Potresti anche essere interessato a 'va_copy'. –