将函数定义为函数指针

时间:2014-08-11 02:32:16

标签: c pointers function-pointers

主要是为了好玩,我决定为我的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。这可能(或类似的东西)可能吗?如果没有,是否有原因(如果这个原因只是&#34;因为它没有被添加到语言&#34;,那很好)?

2 个答案:

答案 0 :(得分:3)

函数指针是一种东西,函数是另一种东西,所以你不能真正使后者成为前者。但是如果你使用一个函数名称,在那里需要一个函数指针,它会产生一个指向函数的指针,所以你可以删除不必要的强制转换,就像WhozCraig在上面的第一条评论中所说的那样。你写了

  

如果我可以做这样的事情,那么在结构中,我可以简单地将func字段设为example_test而不是(test_p)example_test。

可以这样做,其中example_test的定义与你当前代码中的一样......你试过吗?

你也可以转发声明一个函数,如下所示:

typedef int test_func(void); // note no indirection
typedef test_func* test_p;

test_func example_test;

如果你在定义函数时可以使用那种语法会很好,就像在你尝试的语法中一样,但是在C语言中根本没办法这样做...你必须明确地提供返回类型和参数列表。

另一个细节是,当你调用函数指针指向的函数时,你不必取消引用它...这就是你能写的原因

test()

而不是

(*test)()

虽然后者也有效。 (事实上​​,因为尊重被剥夺,(********test)()也有效......但只有在你试图赢得混淆比赛时才这样做。)

答案 1 :(得分:1)

您所描述的是一种元编程。您不是编写代码来明确地解决问题,而是关注一种语法结构,它允许您定义一大堆测试函数,而不会产生不必要的错误。

在Lisp中你会使用宏。在C ++中,您可以使用模板和/或lambda。在C中你使用宏。

所以你需要编写一个宏:

  • 将名称和描述性文字作为参数
  • 定义函数类型的静态变量(使用令牌粘贴从该名称创建)
  • 定义一个函数(使用由标记粘贴创建的名称)

[edit]此时你已经实现了目标:你已经创建了这个函数并给它一个名称(只)是一个函数指针,你可以在结构中使用该名称而不需要强制转换。我建议另外一步,宏也是:

  • 将变量/函数和描述性文本添加到要测试的函数列表中。

然后,您的样板循环遍历调用每个函数的结构,并使用描述性文本报告结果。问题解决了。

有些人不喜欢宏,但他们非常适合这种情况,而且没有其他方法可以在C中做到这一点。在转向C ++之前,我做了类似的事情。