2009-11-28 16 views
5

J'utilise la bibliothèque ffcall (en particulier la bibliothèque avcall de ffcall) pour pousser dynamiquement les paramètres vers les fonctions variadiques. c'est-à-dire que nous avonspointeurs de void et bibliothèque ffcall

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

et nous voulons appeler cette fonction avec des valeurs tirées de l'utilisateur. Pour ce faire, nous créons une version avcall de la fonction:

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

Maintenant, la fonction que je me sers avcall avec est:

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

Et il est utilisé comme ceci:

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

Mais je veux utiliser avcall pour capturer une certaine quantité de valeurs de cette fonction et je ne connais pas cette information à l'avance. Donc, je pensais que je venais de créer un tableau de pointeurs vides et l'espace de malloc en fonction du type:

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"); 
} 

Et av_read_row est juste:

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

J'ai connu un tas de corruption de mémoire erreurs et il semble que ça n'aime pas ce que je fais ici. Je ne peux rien voir de faux avec la façon dont j'ai fait ça, n'est-ce pas? À l'heure actuelle, il n'aime pas quand je tente de libérer les mallocs à l'intérieur de la boucle av_read_row. Quelqu'un peut-il voir ce que je fais mal, si quelque chose?

Merci

+0

Je pense que votre strcat manque quelque chose ... Je ne suis pas vraiment familier avec le truc av_, mais si printf_string est écrasé, vous obtiendrez des résultats désagréables. –

+1

Est-ce (http://www.haible.de/bruno/packages-ffcall.html) le paquet que vous utilisez? –

Répondre

0

Je ne suis pas dans les détails les plus fins du code, mais ne peut dire ce qui suit

  1. En utilisant la pile pour passer un grand nombre d'arguments n'est pas souhaitable, que la pile est limitée. Je ne suis pas sûr si av_stuff vérifie vraiment la limite de la pile.
  2. N'existe-t-il pas une méthode plus simple pour faire la même opération au lieu de pousser la variable à empiler?
1

La seule information que je peux trouver facilement à propos de avcall date de 2001, mais elle suggère POSIX. Si vous pouvez exécuter vos trucs sur Linux, valgrind trouvera vos fautes de mémoire en un tournemain. C'est un outil formidable.