我正在编写单元测试框架(有关详细信息,请参阅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
答案 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;
}