Как вызвать произвольную функцию C, переданную другой функции? - PullRequest
2 голосов
/ 23 сентября 2011

Я пишу фреймворк для юнит-теста (подробнее см. SO ).Или посмотрите код на GitHub .

Безопасный код описывает способ передачи функций произвольных типов.

Но как я могу назвать такойфункционировать, не зная его типов заранее?Предположим, что f не требует ввода, поэтому f() должен работать сам по себе.

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

void* gen_array(fp gen, size_t size) {
    int i, len = gen_int() % 100;

    void* arr = GC_MALLOC(len * size);

    for (i = 0; i < len; i++) {
        arr[i] = gen(NULL);
    }

    return arr;
}

Это должно выглядетькак то так, но я получаю ошибки компилятора:

gcc -o example example.c qc.c qc.h -lgc
In file included from example.c:1:
qc.h:21: error: expected declaration specifiers or ‘...’ before ‘size_t’
In file included from qc.c:1:
qc.h:21: error: expected declaration specifiers or ‘...’ before ‘size_t’
qc.c:23: error: conflicting types for ‘gen_array’
qc.h:21: error: previous declaration of ‘gen_array’ was here
qc.c: In function ‘gen_array’:
qc.c:29: warning: dereferencing ‘void *’ pointer
qc.c:29: error: too many arguments to function ‘gen’
qc.c:29: error: invalid use of void expression
qc.h:21: error: expected declaration specifiers or ‘...’ before ‘size_t’
make: *** [example] Error 1

Ответы [ 5 ]

1 голос
/ 23 сентября 2011

Подумав еще немного, я понимаю, что ваша проблема никогда не сработает.Вы сначала вызываете, пытаясь вызвать пустую функцию без параметров с параметром NULL.Затем вам нужно, чтобы ваш код был более общим.Я поместил пример ниже того, что я имею в виду.Теперь с помощью глобальной переменной

#include <stdio.h>
#include <stdlib.h>

typedef void (*fp)(void);


void * GEN_ARRAY_TEMP;

int gen_int() {
    return 67;
}

void* gen_array(fp gen, size_t size) {
    int i, len = gen_int() % 100;

    void* arr = malloc(len * size);
    void* arr_end = arr + len * size;
    GEN_ARRAY_TEMP = arr;

    while (GEN_ARRAY_TEMP <= arr_end) {
        gen();
        GEN_ARRAY_TEMP+=size;
    }
    return arr;
}

void make_int() {
    (*(int*)GEN_ARRAY_TEMP) = 9;
}

int main() {
    int i;
    int * gen_int_array = (int*) gen_array(make_int, sizeof(int));
    for(i=0;i<67;i++) {
        printf("%d\n",gen_int_array[i]);
    }
}
1 голос
/ 23 сентября 2011

На этой странице предлагается, чтобы указатель функции занял void*. Поэтому, чтобы ваш код компилировался, вы должны передать ему пустой указатель:

typedef void* (*fp)(void*);

doit(fp f) {
   f(NULL);
}

И просто убедитесь, что вызываемая вами функция просто игнорирует параметр.

Вообще говоря, эти указатели общих функций используются для запуска потоков. Указатель void - это просто указатель на структуру, которая содержит фактические параметры.

0 голосов
/ 23 сентября 2011

Для случая, когда ваш указатель на функцию 'fp' имеет тип, который не принимает аргументов и возвращает void, в этом случае вы должны объявить его как:

typedef void (*fp)();  

В указанном выше случае звонок должен быть:

(*gen)();  

Если ваш указатель на функцию 'fp' имеет тип, который принимает 'void *' в качестве аргумента и возвращает void, в этом случае вы должны объявить его как:

typedef void (*fp)(void *);

В приведенном выше случае вызов должен быть:

(*gen)(NULL);  

или любая другая переменная-указатель, которую вы можете передать.

Что касается вашего примера, попробуйте следующее:

typedef void * (*fp)(void *);


void* gen_array(fp gen, size_t size) {
    int i, len = gen_int() % 100;

    void* arr = GC_MALLOC(len * size);

    for (i = 0; i < len; i++) {
        arr[i]  = (*gen)(NULL);
    }

    return arr;
}
0 голосов
/ 23 сентября 2011

У вас есть две проблемы:

Во-первых, qc.h отсутствует <stdlib.h> include.Это необходимо для использования size_t.

Во-вторых, в gen_array вы создаете void *arr, затем пытаетесь разыменовать его как массив (arr[i]).Поскольку компилятор не знает размер элементов вашего массива, он не может заполнить массив.Вы должны обработать его как char *, смещение на arr + size * i и передать его в gen, а не принимать возврат (возврат также должен знать размер структуры):

// ...
char *arr = GC_MALLOC(len * size);

for (int i = 0; i < len; i++) {
    gen(arr + i * size, NULL);
}

return arr;

Это будетконечно, требуется изменить определение типа fp.

0 голосов
/ 23 сентября 2011

Что вам нужно сделать, это обернуть вашу функцию в пустую функцию, например, так:

#include <stdio.h>
typedef void (*fp)(void);

int sum(int x,int y) {return x+y;}

void doit(fp f) {
        f();
}

void func() {
        printf("Hello %d\n",sum(1,2));
}

int main() {
        doit(func);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...