2009-03-30 17 views
60

Ho circa 30 funzioni variadiche. Ognuno accetta un percorso come argomento finale, es .:Passaggio di un'ellissi a un'altra funzione variadica

bool do_foo(struct *f, int q, const char *fmt, ...) 

In ogni funzione, devo verificare che il formato espanso è inferiore o uguale ad una certa dimensione. Quindi, mi trovo a copiare/incollare lo stesso pezzo di codice per verificare quanti caratteri non sono stati stampati vsnprintf(), impostare errno di conseguenza e salvare la scrittura.

Quello che mi piacerebbe fare è scrivere una funzione per fare ciò, che restituirebbe una stringa allocata staticamente (espansa) che è nota per essere una dimensione sicura o una stringa appena inizializzata in caso di errore, che potrebbe essere verificata con NULL . I controlli devono anche determinare se la stringa è un percorso assoluto o relativo, che influenza la dimensione sicura della stringa. È un sacco di codice duplicato e sta iniziando a puzzare.

Esiste un modo per trasferire il contenuto degli elipsis dalla voce della mia funzione a un'altra funzione? O devo prima chiamare lo va_start() e poi passare il va_list alla funzione di supporto?

Edit:

Io non sono affatto contrario a passare il va_list al aiutante, volevo solo fare in modo che nient'altro esisteva. Mi sembra che il compilatore capisca dove iniziano gli argomenti variadici, quindi ero solo curioso di sapere se li avrei passati.

+0

C'è qualche ragione siete avversi a passare il va_list al aiutante? – ojblass

+0

Ho dovuto fare cose simili, ma ho dovuto eliminare alcuni degli argomenti ... non era un codice piacevole da mantenere. – ojblass

risposta

63

Non è possibile, è possibile solo passare gli argomenti come va_list. Vedi lo comp.lang.c FAQ.

In generale, se si scrivono funzioni variadiche (ovvero funzioni che richiedono un numero variabile di argomenti) in C, è necessario scrivere due versioni di ciascuna funzione: una che utilizza i puntini di sospensione (...) e una che prende un va_list. La versione che accetta i puntini di sospensione dovrebbe chiamare va_start, chiamare la versione prendendo uno va_list, chiamare va_end e restituire. Non c'è bisogno di duplicare il codice tra le due versioni della funzione, dato che si chiama l'altra.

+5

Sarebbe bello se scrivessi il codice. –

+0

Cosa devo fare se devo fare cose con 'va_list' due volte? Normalmente, dovrei chiamare 'va_end' e' va_start' tra usi (altrimenti è UB), ma non posso chiamarlo in una funzione che richiede 'va_list':' 'va_start' usato in funzione con argomenti fissi' . –

+1

Non importa, capito - Devo usare 'va_copy' per ogni utilizzo successivo. –

0

Devi passare va_list all'helper.

+1

Questa risposta è un modo per essere utili. Dovrebbe essere espandibile con ulteriori dettagli utili o rimosso. – rjstelling

+0

@rjstelling Ho trovato questa risposta utile quando ho posto la domanda.Se notate, ho indicato che sostanzialmente ho acconsentito a passare la va_list, ma sentivo che potrebbe esserci un modo diverso di farlo. Andrew ha praticamente confermato che non ce n'era uno (nessuna magia da compilatore che potrei usare). Mentre altre risposte sono andate più in profondità, questo ha risposto sufficientemente alla mia domanda. –

9

Probabilmente è possibile utilizzare le macro variadic - in questo modo:

#define FOO(...) do { do_some_checks; myfun(__VA_ARGS__); } while (0) 

NB! Macro Variadic sono solo C99

+0

Stavo guardando quelli, che mi evitano di dover aggiungere un wrapper attorno alla funzione che effettivamente fa la scrittura. –

+0

c99 non è un problema, il mio programma è piuttosto specifico per gcc/linux –

-1

Non so se questo sarà di aiuto, è possibile accedere alle variabili per riferimento. Questo è un po 'un trucco subdolo, ma sfortunatamente non ti permetterà di usare i puntini di sospensione nella definizione della funzione finale.

#include <stdio.h> 

void print_vars(int *n) 
{ 
    int i; 
    for(i=0;i<=*n;i++) 
    printf("%X %d ", (int)(n+i), *(n+i)); 
    printf("\n"); 
} 

void pass_vars(int n, ...) 
{ 
    print_vars(&n); 
} 

int main() 
{ 
    pass_vars(4, 6, 7, 8, 0); 
    return 0; 
} 

sul mio PC che emette

$ ./a.out 
BFFEB0B0 4 BFFEB0B4 6 BFFEB0B8 7 BFFEB0BC 8 BFFEB0C0 0 
+9

Non portatile ... – aschepler

Problemi correlati