如何在C中将函数作为参数传递?

How do you pass a function as a parameter in C?

我想创建一个函数,它对一组数据执行参数传递的函数。如何在C中传递函数作为参数?


宣言

采用函数参数的函数的原型如下所示:

1
void func ( void (*f)(int) );

这说明参数f将是指向具有void返回类型并接受单个int参数的函数的指针。以下函数(print是一个可以作为参数传递给func的函数的示例,因为它是正确的类型:

1
2
3
4
void print ( int x ) {
  printf("%d
"
, x);
}

函数调用

调用带有函数参数的函数时,传递的值必须是指向函数的指针。为此,请使用函数名(不带括号):

1
func(print);

调用func,将print函数传递给它。

功能体

与任何参数一样,func现在可以在函数体中使用参数的名称来访问参数的值。假设func将应用传递给数字0-4的函数。首先,考虑直接调用print的循环是什么样子的:

1
2
3
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}

由于func的参数声明说f是指向所需函数的指针的名称,我们首先回忆一下,如果f是指针,那么*ff指向的东西(在本例中是print函数)。因此,只要用*f替换上面循环中出现的每个打印:

1
2
3
4
5
void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}

摘自http://math.hws.edu/bridgeman/courses/331/f05/paddles/c-c++-notes.html


这个问题已经有了定义函数指针的答案,但是它们可能会变得非常混乱,特别是当您要在应用程序中传递它们时。为了避免这种不愉快,我建议您将函数指针类型化为更可读的类型。例如。

1
typedef void (*functiontype)();

声明一个返回void且不接受参数的函数。要创建指向此类型的函数指针,现在可以执行以下操作:

1
2
3
4
void dosomething() { }

functiontype func = &dosomething;
func();

对于返回int并接受char的函数

1
typedef int (*functiontype2)(char);

并使用它

1
2
3
4
int dosomethingwithchar(char a) { return 1; }

functiontype2 func2 = &dosomethingwithchar
int result = func2('a');

有一些库可以帮助将函数指针转换为可读性好的类型。Boost函数库很棒,值得您付出努力!

1
boost::function<int (char a)> functiontype2;

比上面好多了。


由于C++ 11,您可以使用函数库以简洁和通用的方式来实现这一点。语法是,例如,

1
std::function<bool (int)>

其中bool是单参数函数的返回类型,其第一个参数是int类型。

我在下面提供了一个示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// g++ test.cpp --std=c++11
#include <functional>

double Combiner(double a, double b, std::function<double (double,double)> func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

但是,有时使用模板函数更方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// g++ test.cpp --std=c++11

template<class T>
double Combiner(double a, double b, T func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}


将函数的地址作为参数传递给另一个函数,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

void print();
void execute(void());

int main()
{
    execute(print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void f()) // receive address of print
{
    f();
}

我们还可以使用函数指针传递函数作为参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

void print();
void execute(void (*f)());

int main()
{
    execute(&print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void (*f)()) // receive address of print
{
    f();
}

您需要传递一个函数指针。语法有点繁琐,但一旦熟悉它,它就非常强大。


它实际上不是一个函数,但它是一段本地化的代码。当然,它不会只传递结果。如果传递给事件调度器以便稍后运行(因为结果是现在计算的,而不是在事件发生时计算的),它将不起作用。但是,如果您只想将代码本地化到一个地方,那么它确实会将代码本地化到一个地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>

int IncMultInt(int a, int b)
{
    a++;
    return a * b;
}

int main(int argc, char *argv[])

{
    int a = 5;
    int b = 7;

    printf("%d * %d = %d
"
, a, b, IncMultInt(a, b));

    b = 9;

    // Create some local code with it's own local variable
    printf("%d * %d = %d
"
, a, b,  ( { int _a = a+1; _a * b; } ) );

    return 0;
}


函数可以作为函数指针"传递",如6.7.6.3p8所示:"参数声明为"函数返回类型"应调整为"指向函数返回类型的指针",如6.3.2.1所示。"。例如:

1
void foo(int bar(int, int));

相当于:

1
void foo(int (*bar)(int, int));