主要是为了好玩,我决定为我的C代码编写自己的最小测试框架 . 我使用基本 struct
作为测试信息,创建一个测试数组 struct
然后迭代它们以运行所有测试 . 对于相当优雅(imho)的解决方案而言,这相当于非常少量的工作 .
然而,有点恼人的一件事是我无法弄清楚如何将函数定义为函数指针而不是定义函数,然后再创建函数指针 .
我有以下(工作得很好):
typedef int (* test_p) (void);
struct test {
char * desc;
test_p func;
};
int
example_test (void) {
puts("This is a test");
return 0;
}
void
run_test (char * test_name, test_p test) {
printf("Testing %s\t\t\t[ PEND ]\r", test_name);
char * test_result = (test() ? "FAIL" : "PASS");
printf("Testing %s\t\t\t[ %s ]\n", test_name, test_result);
}
int
main (void) {
struct test test_list [] = {
{ "example test", (test_p )example_test }
};
for ( int i = 0; i < 1; i ++ ) {
run_test(test_list[i].desc, test_list[i].func);
}
return 0;
}
但是,我希望我可以在 struct
中删除对转换的需要,而是将函数定义为从头开始的函数指针 . 以下是我希望如何工作的示例(假设许多与上面相同的内容):
test_p
example_test = {
puts("This is a test");
return 0;
}
如果我可以做这样的事情,那么在 struct
中,我可以简单地将 func
字段设为 example_test
而不是 (test_p )example_test
. 这可能(或类似的东西)可能吗?如果没有,是否有原因(如果这个原因只是"because it wasn't added to the language",那很好)?
2 回答
函数指针是一种东西,函数是另一种东西,所以你不能真正使后者成为前者 . 但是如果你使用一个函数名称,在那里需要一个函数指针,它会产生一个指向函数的指针,所以你可以删除不必要的强制转换,就像WhozCraig在上面的第一条评论中所说的那样 . 你写
您可以这样做,example_test定义就像您当前的代码一样......你试过吗?
你也可以转发声明一个函数,如下所示:
如果您在定义函数时可以使用这种语法,就像在您尝试的语法中那样,那将是很好的,但是在C中根本无法做到这一点...您必须显式提供返回类型和参数列表 .
另一个细节是,当你调用函数指针指向的函数时,你不必取消引用它...这就是你能写的原因
代替
虽然后者也有效 . (事实上,因为尊重被剥夺了,
(********test)()
也有效......但只有在你试图赢得混淆比赛时才这样做 . )你所描述的是一种元编程 . 您不是编写代码来明确地解决问题,而是关注一种语法结构,它允许您定义一大堆测试函数而不会产生不必要的瑕疵 .
在Lisp中你会使用宏 . 在C中,您可以使用模板和/或lambda . 在C中,您使用宏 .
所以你需要编写一个宏:
将名称和描述性文本作为参数
定义函数类型的静态变量(使用令牌粘贴从该名称创建)
定义一个函数(使用由标记粘贴创建的名称)
[编辑]此时你已经实现了目标:你已经创建了函数并给它一个名称(只)是一个函数指针,你可以在结构中使用该名称而不需要强制转换 . 我建议另外一步,宏也:
然后,您的样板循环遍历调用每个函数的结构,并使用描述性文本报告结果 . 问题解决了 .
有些人不喜欢宏,但它们非常适合这种情况,而且没有其他方法可以用C来做 . 我在转向C之前做了类似的事情 .