2009-03-30 16 views
60

Tengo aproximadamente 30 funciones variadas. Cada uno acepta un camino como el argumento final, por ejemplo .:Pasando una elipsis a otra función variable

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

En cada función, tengo que comprobar que el formato expandido es menos de o igual a un cierto tamaño. Entonces, me encuentro copiando/pegando el mismo fragmento de código para verificar cuántos caracteres vsnprintf() no se imprimieron, establecí errno en consecuencia y salgo de la escritura.

Lo que me gustaría hacer es escribir una función para hacer esto, que devolvería una cadena estáticamente asignada (expandida) que se sabe que es un tamaño seguro, o una cadena recién inicializada en falla, que podría verificarse contra NULL . Los controles también deben determinar si la cadena es una ruta absoluta o relativa, lo que influye en el tamaño seguro de la cadena. Es un montón de código duplicado y está empezando a oler.

¿Hay alguna manera de que pueda pasar el contenido de la elipsis de la entrada de mi función a otra función? ¿O debo llamar primero al va_start() y luego pasar el va_list a la función auxiliar?

Editar:

No estoy en absoluto en contra de pasar el va_list al ayudante, sólo quería asegurarse de que nada más existía. Me parece que el compilador entiende dónde comienzan los argumentos variados, así que estaba curioso si podía decir que los pasara.

+0

¿Hay alguna razón por la que está pasando adversa a la va_list al ayudante? – ojblass

+0

He tenido que hacer cosas similares, pero tuve que quitar algunos de los argumentos ... no era un código agradable de mantener. – ojblass

Respuesta

63

No puede, solo puede pasar los argumentos como va_list. Vea el comp.lang.c FAQ.

En general, si escribe funciones variadic (es decir, funciones que toman un número variable de argumentos) en C, debe escribir dos versiones de cada función: una que toma puntos suspensivos (...) y una que toma un va_list. La versión que toma una elipsis debe llamar al va_start, llamar a la versión tomando un va_list, llamar al va_end, y regresar. No es necesario duplicar el código entre las dos versiones de la función, ya que una llama a la otra.

+5

Sería bueno si escribió el código. –

+0

¿Qué debo hacer si necesito hacer cosas con 'va_list' dos veces? Normalmente, tendría que llamar 'va_end' y' va_start' entre usos (de lo contrario es UB), pero no puedo llamarlo en una función que toma 'va_list':''va_start 'usado en función con argumentos fijos' . –

+1

No importa, lo descubrí - Necesito usar 'va_copy' para cada uso posterior. –

0

Tienes que pasar va_list al ayudante.

+1

Esta respuesta es muy concisa para ser útil. Debería expandirse con detalles útiles adicionales o eliminarse. – rjstelling

+0

@rjstelling Encontré esta respuesta útil cuando hice la pregunta.Si lo notas, indiqué que básicamente me limité a aprobar la lista va_, pero sentí que podría haber una forma diferente de hacerlo. Andrew prácticamente confirmó que no había uno (no podía usar magia de compilación). Mientras otras respuestas fueron más profundas, esto respondió mi pregunta de manera suficiente. –

9

Probablemente se puede utilizar macros variadic - como esto:

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

NB! Las macros de variables son solo C99

+0

Estaba mirando esos, eso me ahorra tener que agregar un envoltorio alrededor de la función que realmente hace la escritura. –

+0

c99 no es problema, mi programa es más bien específico de gcc/linux –

-1

No sé si esto ayudará, puede acceder a las variables por referencia. Este es un truco furtivo, pero desafortunadamente no le permitirá usar puntos suspensivos en la definición final de la función.

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

en mi PC emite

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

No portátil ... – aschepler

Cuestiones relacionadas