пустые указатели и библиотека ffcall - PullRequest
5 голосов
/ 29 ноября 2009

Я использую библиотеку ffcall (в частности, пакет avcall для ffcall), чтобы динамически передавать параметры в функции с переменными параметрами. у нас есть

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

и мы хотим вызвать эту функцию со значениями, взятыми у пользователя. Для этого мы создаем версию функции avcall:

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

Теперь я использую функцию avcall:

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

И это используется так:

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

Но я хочу использовать avcall для захвата определенного количества значений из этой функции, и я не знаю эту информацию заранее. Поэтому я подумал, что я просто создам массив указателей void, а затем пространство malloc в соответствии с типом:

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

А av_read_row это просто:

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

Я столкнулся с кучей ошибок повреждения памяти, и мне кажется, что мне не нравится то, что я здесь делаю. Я не могу обнаружить ничего плохого в том, как я это сделал, не так ли? На данный момент это не нравится, когда я пытаюсь освободить mallocs внутри av_read_row цикла while. Кто-нибудь может увидеть, что я делаю не так, если что-нибудь?

Спасибо

Ответы [ 2 ]

1 голос
/ 17 января 2010

Единственная информация, которую я могу легко найти о avcall, относится к 2001 году, но она действительно предлагает POSIX. Если вы можете запустить свои вещи в Linux, valgrind быстро обнаружит ошибки памяти. Это потрясающий инструмент.

0 голосов
/ 15 января 2010

Я не вдавался в подробности кода, но могу сказать следующее

  1. Использование стека для передачи большого количества аргументов не рекомендуется, так как стек ограничен. Я не уверен, что av_stuff действительно проверяет ограничение стека.
  2. Нет ли более простого способа выполнить ту же операцию вместо помещения переменной в стек?
...