2010-08-20 13 views
71

Così ho 2 funzioni che entrambi hanno argomenti similiPassando argomenti variabili a un'altra funzione che accetta un elenco di argomenti variabili

void example(int a, int b, ...); 
void exampleB(int b, ...); 

Ora example chiamate exampleB, ma come posso passare lungo le variabili nella lista di argomenti variabili senza modificare exampleB (dato che è già utilizzato anche altrove).

+5

possibile duplicato di [Inoltra un'invocazione di una funzione variadica in C] (http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c) –

+0

Well la soluzione su quello stava usando vprintf, e non è questo il caso. –

risposta

79

Non è possibile farlo direttamente; è necessario creare una funzione che prende un va_list:

#include <stdarg.h> 

static void exampleV(int b, va_list args); 

void example(int a, int b, ...) 
{ 
    va_list args; 
    va_start(args, b); 
    exampleV(b, args); 
    va_end(args); 
} 

void exampleB(int b, ...) 
{ 
    va_list args; 
    va_start(args, b); 
    exampleV(b, args); 
    va_end(args); 
} 

static void exampleV(int b, va_list args) 
{ 
    ...whatever you planned to have exampleB do... 
    ...except it calls neither va_start nor va_end... 
} 
+1

Sospetto che dovevo fare qualcosa del genere, problema è la funzione di esempio è fondamentalmente un wrapper per vsprintf e non molto altro:/ –

+0

@Xeross: Nota che questo non cambia le specifiche esterne di ciò che fa l'esempioB - cambia solo l'interno implementazione. Non sono sicuro di quale sia il problema. –

+1

L'ho gestito in modo simile a questo, grazie. –

14

si dovrebbero creare versioni di queste funzioni che accettano una va_list e le superano. Guarda vprintf come esempio:

int vprintf (const char * format, va_list arg); 
-1

Utilizzando il nuovo standard C++ 0x, si può essere in grado di ottenere questo fatto utilizzando i modelli variadic o anche convertire quel vecchio codice per la nuova sintassi modello senza rompere qualsiasi cosa.

+0

sfortunatamente questo non è possibile in tutti i casi - prova ad usare lambdas – serup

0

In base al commento che stai tagliando vsprintf e che questo è taggato come C++, suggerirei di non provare a farlo, ma invece di cambiare l'interfaccia per usare gli iostream di C++. Hanno vantaggi rispetto alla linea di funzioni print, come la sicurezza del tipo e la possibilità di stampare elementi che printf non sarebbero in grado di gestire. Alcune rielaborazioni ora potrebbero salvare una quantità significativa di dolore in futuro.

+0

A quali vantaggi ti riferisci? – cjcurrie

+0

@cjcurrie: il vantaggio è la sicurezza del tipo, anche con tipi definiti dall'utente. Le funzioni C non possono gestire i tipi definiti dall'utente, naturalmente. –

2

Incidentalmente, molte implementazioni C hanno una variazione v? Printf interna che IMHO avrebbe dovuto essere parte dello standard C. I dettagli esatti variano, ma un'implementazione tipica accetterà una struttura contenente un puntatore a funzione di output di carattere e informazioni che dicono che cosa dovrebbe accadere. Ciò consente a printf, sprintf e fprintf di utilizzare tutti lo stesso meccanismo "core". Ad esempio, vsprintf potrebbe essere qualcosa di simile:

 
void s_out(PRINTF_INFO *p_inf, char ch) 
{ 
    (*(p_inf->destptr)++) = ch; 
    p_inf->result++; 
} 

int vsprintf(char *dest, const char *fmt, va_list args) 
{ 
    PRINTF_INFO p_inf; 
    p_inf.destptr = dest; 
    p_inf.result = 0; 
    p_inf.func = s_out; 
    core_printf(&p_inf,fmt,args); 
} 

La funzione core_printf chiama poi p_inf-> func per ogni carattere da emettere; la funzione di output può quindi inviare i caratteri alla console, un file, una stringa o qualcos'altro. Se la propria implementazione espone la funzione core_printf (e qualsiasi altro meccanismo di installazione utilizzi), è possibile estenderla con tutti i tipi di variazioni.

1

Volevo anche avvolgere printf e trovato una risposta utile qui:

How to pass variable number of arguments to printf/sprintf

non era affatto interessato alle prestazioni (sono sicuro che questo pezzo di codice può essere migliorata in un certo numero di modi, si sentono liberi di farlo :)), questo è per debugprinting generale, solo così ho fatto questo:

//Helper function 
std::string osprintf(const char *fmt, ...) 
{ 
    va_list args; 
    char buf[1000]; 
    va_start(args, fmt); 
    vsnprintf(buf, sizeof(buf), fmt, args); 
    va_end(args); 
    return buf; 
} 

che ho poi posso usare come questo

Point2d p; 

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y); 
instead of for example: 
cout << "Point2d: (" << setw(3) << p.x << ", " << p.y << ")"; 

Gli strati di C++ sono belli per alcuni aspetti, ma praticamente diventano orribili se si desidera stampare qualcosa di simile con alcune stringhe piccole come parentesi, due punti e virgole inserite tra i numeri.

4

Forse throwin una roccia in uno stagno qui, ma sembra funzionare abbastanza bene con C++ 11 modelli variadic:

#include <stdio.h> 

template<typename... Args> void test(const char * f, Args... args) { 
    printf(f, args...); 
} 

int main() 
{ 
    int a = 2; 
    test("%s\n", "test"); 
    test("%s %d %d %p\n", "second test", 2, a, &a); 
} 

Per lo meno, funziona con g++.

Problemi correlati