-1

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

例如,如果我有以下代码:

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

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

4

6 回答 6

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++如何做虚成员函数。用哈希表替换方法结构,你就有了 Objective-C 的方法调度。与变量指针一样,函数指针可以让您以有价值的方式抽象事物,从而使代码更加紧凑和灵活。但是,从最简单的例子来看,这种力量并不是很明显。

于 2013-10-07T01:10:38.190 回答
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 还是您能想到的任何其他方式。

于 2013-10-07T01:15:47.230 回答
1

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

它的签名是

void qsort (void* base, size_t num, size_t size,
        int (*compar)(const void*,const void*));
于 2013-10-07T01:02:49.647 回答
1

它们减少了模块之间的依赖关系。有时库必须查询调用代码的事物(这些对象是否相等?它们是否按特定顺序?)。但是,如果不使库 (a) 依赖于调用代码和 (b) 非泛型,就无法硬编码对正确函数的调用。

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

于 2013-10-07T01:03:21.380 回答
1

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

于 2013-10-07T01:07:22.417 回答
1

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

于 2013-10-07T01:07:42.550 回答