传递函数指针
Posted
技术标签:
【中文标题】传递函数指针【英文标题】:Passing Function Pointer 【发布时间】:2013-10-25 10:02:00 【问题描述】:对于如何将指针传递给指针函数,我有点困惑。我有一个函数,它带有一个指向我理解没有问题的函数的指针 (ExecBlock
)。但是我得到了另一个函数原型(ExecBlock2
),它接受取消引用的指针(我不确定它到底是什么),并且如果传递的函数有任何参数,它也会接受参数。如果有人可以解释优先级以及取消引用指针函数会做什么。那不只是传递函数本身吗?在这种情况下(void *)
做了什么?
int ExecBlock (void (*f) (void), int isSet)
return ExecBlock2( HOW TO PASS HERE? , NULL, isSet);
int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
... more code
【问题讨论】:
检查this answer 【参考方案1】:void (*f) (void)
表示指向函数的指针,没有返回 void 的参数。
void *(*f)(void *)
表示指向函数的指针,该函数接受一个 void 指针并返回一个 void 指针。
由于类型不同,编译器不允许您在不强制转换的情况下将一个传递给另一个。 (请注意,强制转换在这里并不是真正的正确答案,正如@detly 指出的那样,会导致未定义的行为。)
至于解引用函数指针,您不必在函数指针之前显式放置一个“*”来调用它。例如,你可以调用你的函数指针 f 只是这样做
f();
函数指针示例
假设您有一个函数f
,您想将它传递给一个名为takes_a_function
的函数。
takes_a_function
可能会有类似
void takes_a_function(void (*f)(void *data), void *data);
注意takes_a_function
有两个参数,一个函数指针和一个指向某些数据的空指针。另请注意,函数f
恰好将 void 指针作为参数。这个想法是您可以将数据传递给takes_a_function
,它会将其传递给f
。例如,takes_a_function
可以这样定义
void takes_a_function(void (*f)(void *), void *data)
f(data);
现在,让我们编写一个函数来传递给takes_a_function
。我们的函数只会打印一个传递给它的 int。
void prints_an_int(void *data)
// The idiom for converting a void pointer to another kind
// of pointer. NO NEED TO CAST. Note this behavior is only
// defined if the pointer data really does point to an int.
int *i = data;
printf("%d", *i);
int i = 0;
takes_a_function(prints_an_int, &i);
关于这个例子的几个关键点:
prints_an_int
与 takes_a_function
期望的函数指针具有相同的类型。无需投射。
无需使用&
运算符来创建对函数的引用。这就是为什么我们可以直接将prints_an_int
传递给takes_a_function
。但我们也可以说takes_a_function(&prints_an_int, &i)
,也是一样的。
void*
基本上意味着“指向未知类型的指针”。要实际使用它,您必须将类型为void*
的变量分配给另一个您期望其类型的指针变量。仅当您实际传入正确的指针类型时,才能保证有效!在这个例子中,我们可以将data
分配给int*
,因为data 确实指向一个int。如果您想要更多的数据而不仅仅是一个整数,一种常见的模式是创建您自己的结构类型,其中包含您想要的所有字段,然后将其传递。
作为一种特殊情况,编译器在将 void 指针分配给其他指针时不要求您进行强制转换,反之亦然。但同样,只有最终将 void 指针转换回正确的类型时,您才会得到定义的行为。
【讨论】:
“你不能在没有强制转换的情况下将一个传递给另一个。”不!在有效的 C 程序中,您根本无法将一个传递给另一个 - 这是未定义的行为。 @detly 很公平,我会编辑。我的意思是说,compiler 不允许你在没有强制转换的情况下将一个传递给另一个。并不是说结果是定义的行为。 @ThePedestrian,您对括号的优先级和位置是正确的。但是您不能将 f 传递给 ExecBlock2,因为 ExecBlock2 需要不同的类型。 @ThePedestrian 强制转换的问题是编译器假设你完全知道你在做什么,它会停止抱怨并编译你的代码。但它首先抱怨是有充分理由的。重新考虑为什么要尝试传递不兼容的类型并设计更好的解决方案是一个更好的主意。我将编辑我的答案以包含函数指针的通用模式。 你是对的。我刚刚发现了这一点。看来我需要创建某种存根才能正确执行我的功能。【参考方案2】:例如你有一个函数
void * abc(void *)
//...
int ExecBlock (void (*f) (void), int isSet)
return ExecBlock2( abc , NULL, isSet); //use name of the function which have void * as parameter type list and return type void *
int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
... more code
见function-pointers
【讨论】:
以上是关于传递函数指针的主要内容,如果未能解决你的问题,请参考以下文章