所以,我正在查看函数指针,在我看到的例子中,特别是在这个答案中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
如果是这样,那么为什么你需要使用它们,那么它们的用途是什么? (为什么你需要将函数指针传递给其他函数)
答案 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函数。