为什么函数指针有用?

时间:2013-10-07 00:59:41

标签: c function pointers

所以,我正在查看函数指针,在我看到的例子中,特别是在这个答案中here。他们似乎相当多余。

例如,如果我有这段代码:

int addInt(int n, int m) {
    return n+m;
}
int (*functionPtr)(int,int);
functionPtr = &addInt;
int sum = (*functionPtr)(2, 3); // sum == 5

在这看来,创建函数指针没有任何意义,这样做会不会更容易?

int sum = addInt(2, 3); // sum == 5

如果是这样,那么为什么你需要使用它们,那么它们的用途是什么? (为什么你需要将函数指针传递给其他函数)

6 个答案:

答案 0 :(得分:3)

指针的简单示例似乎同样没用。当你开始做更复杂的事情时,它会有所帮助。例如:

// Elsewhere in the code, there's a sum_without_safety function that blindly
// adds the two numbers, and a sum_with_safety function that validates the 
// numbers before adding them.

int (*sum_function)(int, int);
if(needs_safety) {
    sum_function = sum_with_safety;
}
else {
    sum_function = sum_without_safety;
}
int sum = sum_function(2, 3);

或者:

// This is an array of functions. We'll choose which one to call based on 
// the value of index.
int (*sum_functions)(int, int)[] = { ...a bunch of different sum functions... };
int (*sum_function)(int, int) = sum_functions[index];
int sum = sum_function(2, 3);

或者:

// This is a poor man's object system. Each number struct carries a table of 
// function pointers for various operations; you can look up the appropriate 
// function and call it, allowing you to sum a number without worrying about
// exactly how that number is stored in memory.

struct number {
    struct {
        int (*sum)(struct number *, int);
        int (*product)(struct number *, int);
        ...
    } * methods;
    void * data;
};

struct number * num = get_number();
int sum = num->methods->sum(number, 3);

最后一个例子基本上是C ++如何处理虚拟成员函数。将方法struct替换为哈希表,并使用Objective-C的方法分派。与变量指针一样,函数指针允许您以有价值的方式抽象事物,使代码更加紧凑和灵活。但是,从最简单的例子来看,这种力量并不是很明显。

答案 1 :(得分:2)

它们是C中最有用的东西之一!它们允许您制作更多模块化软件。

回调

例如

typedef void (*serial_data_callback)(int length, unsigned char* data);


void serial_port_data_received(serial_data_callback callback)
{
   on_data_received = callback;
}

void data_received(int length, unsigned char* data)
{
   if(on_data_received != NULL) on_data_received(length, data);
}

这意味着在您的代码中您可以使用常规串行例程.....那么您可能有两件事使用串行,modbus和终端

serial_port_data_received(modbus_handle_data);
serial_port_data_received(terminal_handle_data);

他们可以实现回调函数并做适当的事情。

它们允许面向对象的C代码。这是创建“接口”的简单方法,然后每个具体类型可能实现不同的东西。为此,通常你会有一个结构,它将包含函数指针,然后是实现每个函数指针的函数,以及一个创建函数,它将使用正确的函数设置函数指针。

   typedef struct
    {
       void (*send)(int length, unsigned char* data);
    } connection_t;

    void connection_send(connection_t* self, int length, unsigned char* data)
    {
       if(self->send != NULL) self->send(length, data);
    }

    void serial_send(int length, unsigned char* data)
    {
     // send
    }

    void tcp_send(int length, unsgined char* data)
    {
    // send
    }


void create_serial_connection(connection_t* connection)
{
   connection->send = serial_send;
}

然后其他代码可以使用connection_t而无需关心它是通过串口,tcp还是其他任何你可以提出的。

答案 2 :(得分:1)

如果您正在编写用户输入函数的库,该怎么办?像qsort一样可以在任何类型上工作,但用户必须编写并提供比较函数。

它的签名是

void qsort (void* base, size_t num, size_t size,
        int (*compar)(const void*,const void*));

答案 3 :(得分:1)

它们减少了模块之间的依赖关系。有时候一个库必须查询调用代码的东西(这些对象是否相同?它们是按照一定的顺序吗?)。但是你不能硬编码调用正确的函数而不使库(a)依赖于调用代码和(b)非泛型。

函数指针提供了所有缺失的信息,同时保持库模块独立于可能使用它的任何代码。

答案 4 :(得分:1)

当API需要回调给应用程序时,它们是必不可少的。

答案 5 :(得分:1)

另一个用途是实现事件发射器或信号处理器:callback函数。