Tendo ad evitare i vararg, tranne in una circostanza specifica in cui è molto utile. Le argomentazioni variabili non offrono davvero tanto beneficio oltre a quello che può essere fatto dalle singole chiamate di funzione, specialmente nel tuo caso.
In termini di leggibilità (e di solito ciò che preferisco rispetto alla velocità non elaborata salvo casi molto specifici), non vi è alcuna differenza tra le seguenti due opzioni (ho aggiunto un conteggio alle versioni varargs poiché è necessario un contare o sentinella per rilevare la fine dei dati):
update(2, FIELD_NAME1, 10, FIELD_NAME2, 20);
update(3, FIELD_NAME3, 10, FIELD_NAME4, 20, FIELD_NAME5, 30);
/* ========== */
update(FIELD_NAME1, 10);
update(FIELD_NAME2, 20);
update(FIELD_NAME3, 10);
update(FIELD_NAME4, 20);
update(FIELD_NAME5, 30);
infatti, come la versione varargs si allunga, è necessario dividerlo in ogni caso, per la formattazione:
update(5,
FIELD_NAME1, 10,
FIELD_NAME2, 20,
FIELD_NAME3, 10,
FIELD_NAME4, 20,
FIELD_NAME5, 30);
Doing il modo "una chiamata per nome di campo" risulta in un codice più semplice i n la funzione stessa e non compromette la leggibilità delle chiamate. Inoltre, consente al compilatore di rilevare correttamente alcuni errori che non è in grado di fare per vararg, come tipi errati o una mancata corrispondenza tra il conteggio fornito dall'utente e il conteggio effettivo.
Se davvero necessario essere in grado di chiamare una singola funzione per farlo, mi piacerebbe optare per:
void update (char *k1, int v1) {
...
}
void update2 (char *k1, int v1, char *k2, int v2) {
update (k1, v1);
update (k2, v2);
}
void update3 (char *k1, int v1, char *k2, int v2, char *k3, int v3) {
update (k1, v1); /* or these two could be a single */
update (k2, v2); /* update2 (k1, v1, k2, v2); */
update (k3, v3);
}
/* and so on. */
Si potrebbe anche fare le funzioni di livello superiore, come le macro, se si preferisce, senza perdere la sicurezza del tipo.
L'unico posto in cui tendo ad usare le funzioni varargs è quando si fornisce la stessa funzionalità di printf()
- ad esempio, ho dovuto occasionalmente scrivere librerie di logging con funzioni come logPrintf()
che forniscono la stessa funzionalità. Non riesco a pensare a qualsiasi altra nel mio lungo (e intendo, tempo lungo :-) al carbone che ho avuto bisogno di usarlo.
Per inciso, se decidi di utilizzare vararg, tendo ad occuparmi delle sentinelle anziché dei conteggi poiché ciò impedisce la mancata corrispondenza durante l'aggiunta dei campi. Si potrebbe facilmente dimenticare di regolare il conteggio e finire con:
update (2, k1, v1, k2, v2, k3, v3);
quando si aggiunge, che è insidioso perché salta in silenzio k3/v3, oppure:
update (3, k1, v1, k2, v2);
durante l'eliminazione, che è quasi certamente fatale per il buon funzionamento del tuo programma.
Avere una sentinella impedisce questo (a patto che non si dimentichi la sentinella, ovviamente):
update (k1, v1, k2, v2, k3, v3, NULL);
quindi passare una grande stringa in un formato noto. Le stringhe sono più facili da serializzare e molto portabili. Devi solo definire un formato per passarli in - XMl è uno (anche se pesante), o farebbe semplicemente un semplice CSV. – gbjbaanb
+1 a gbjbaanb - guarda a (x) printf - la più bella implementazione di varags conosciuta :) – KevinDTimm