如何调用传递给另一个函数的任意C函数?

时间:2011-09-23 01:34:51

标签: c function pointers

我正在编写单元测试框架(有关详细信息,请参阅SO)。或者查看GitHub处的代码。

Safer Code描述了一种传递任意类型函数的方法。

但是如何在事先不知道其类型的情况下调用这样的函数呢?假设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 个答案:

答案 0 :(得分:1)

该页面建议您将函数指针设为void*。因此,为了编译代码,必须向它传递一个void指针:

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

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

只需确保您调用的函数忽略该参数。

一般来说,这些通用函数指针用于启动线程。 void指针只是一个指向保存实际参数的结构的指针。

答案 1 :(得分:1)

在考虑了更多之后我意识到你的问题,你的上述代码永远不会有效。 您首先调用尝试使用参数NULL调用没有参数的void函数。接下来,您需要更加通用的代码。我在下面的例子中放了一个例子。现在使用全局变量

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

答案 2 :(得分:0)

你需要做的是将函数包装在像

这样的void函数中
#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);
}

答案 3 :(得分:0)

你有两个问题:

首先,qc.h缺少<stdlib.h>包含。使用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类型定义。

答案 4 :(得分:0)

对于指向函数'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;
}