2009-11-28 12 views
5

estoy usando el ffcall (específicamente el paquete de avcall ffcall) biblioteca para empujar de forma dinámica los parámetros a funciones variadic. es decir, tenemospunteros void y biblioteca ffcall

int blah (char *a, int b, double c, ...); 

y queremos llamar a esta función con los valores tomados del usuario. Para ello, creamos una versión avcall de la función:

int av_blah (char *a, int b, double c, char **values, int num_of_values) 
{ 
    av_alist alist; 
    int i, ret; 
    av_start_int (alist, &blah, &ret); //let it know which function 
    av_ptr (alist, char*, a); // push values onto stack starting from left 
    av_int (alist, b); 
    av_double (alist, c); 
    for (i=0;i<num_of_values;i++) 
    { 
     // do what you want with values and add to stack 
    } 
    av_call (alist); //call blah() 

    return (ret); 
} 

Ahora, la función que estoy usando avcall con es:

int read_row (struct some_struct *a, struct another_struct *b[], ...); 

y se utiliza de esta manera:

struct some_struct a; 
struct another_struct **b = fill_with_stuff(); 

char name[64]; 
int num; 
while (read_row (&a, b, name, &num)==0) 
{ 
    printf ("name=%s, num=%d\n", name, num); 
} 

Pero quiero usar avcall para capturar una cierta cantidad de valores de esta función y no sé esta información de antemano. Así que pensé que acababa de crear una matriz de punteros void y luego el espacio malloc según el tipo:

char printf_string[64]=""; //need to build printf string inside av_read_row() 
void **vals = Calloc (n+1, sizeof (void*)); //wrapper 
while (av_read_row (&a, b, vals, n, printf_string) == 0) 
{ 
    // vals should now hold the values i want 
    av_printf (printf_string, vals, n); //get nonsense output from this 
    // free the mallocs which each vals[i] is pointing to 
    void **ptrs = vals; 
    while (*ptrs) { 
     free (*ptrs); //seg faults on first free() ? 
     *ptrs=NULL; 
     ptrs++; 
    } 
    //reset printf_string 
    printf_string[0]='\0'; 
    printf ("\n"); 
} 

Y av_read_row es simplemente:

int av_read_row (struct some_struct *a, struct another_struct *b[], void **vals, int num_of_args, char *printf_string) 
{ 
    int i, ret; 
    av_alist alist; 

    av_start_int (alist, &read_row, &ret); 
    av_ptr (alist, struct some_struct *, a); 
    av_ptr (alist, struct another_struct **, b); 

    for (i=0;i<num_of_args;i++) 
    { 
     switch (type) //for simplicity 
     { 
      case INT: { 
       vals[i] = Malloc (sizeof (int)); 
       av_ptr (alist, int*, vals[i]); 
       strcat (printf_string, "%d, "); 
       break; 
      } 
      case FLOAT: { 
       //Same thing 
      } 
      //etc 
     } 
    } 

    av_call (alist); 
    return (ret); 
} 

que han estado experimentando un montón de corrupción de memoria errores y parece que no le gusta lo que estoy haciendo aquí. No veo nada malo con la forma en que hice esto, ¿o sí? Por el momento, no me gusta cuando intento liberar los mallocs dentro del ciclo while av_read_row. ¿Alguien puede ver lo que estoy haciendo mal, en todo caso?

Gracias

+0

Creo que a su strcat le falta algo ... No estoy muy familiarizado con las cosas av_, pero si printf_string se sobrescribe obtendrá algunos resultados desagradables. –

+1

¿Es este (http://www.haible.de/bruno/packages-ffcall.html) el paquete que está utilizando? –

Respuesta

0

que no entra en los detalles más finos del código, pero se puede decir lo siguiente

  1. que utilizan la pila para pasar gran número de argumentos no es aconsejable, ya que la pila es limitado. No estoy seguro de si av_stuff realmente verifica el límite de la pila.
  2. ¿No hay un método más simple para hacer la misma operación en lugar de presionar la variable para apilar?
1

La única información que puedo encontrar fácilmente sobre avcall es de 2001, pero sugiere POSIX. Si puede ejecutar sus cosas en Linux, valgrind encontrará sus fallas de memoria en un santiamén. Es una excelente herramienta.