函数指针有什么意义?
我很难看出函数指针的实用性。我想它在某些情况下可能有用(毕竟它们存在),但我想不出使用函数指针更好或不可避免的情况。
您能否举一些函数指针(在 C 或 C++ 中)的良好使用示例?
I have trouble seeing the utility of function pointers. I guess it may be useful in some cases (they exist, after all), but I can't think of a case where it's better or unavoidable to use a function pointer.
Could you give some example of good use of function pointers (in C or C++)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
我对它们的主要用途是回调:当您需要保存有关函数的信息以稍后调用时。
假设你正在写《炸弹人》。人扔下炸弹 5 秒后,炸弹就会爆炸(调用
explode()
函数)。现在有两种方法可以做到这一点。一种方法是“探测”屏幕上的所有炸弹,看看它们是否准备好在主循环中爆炸。
另一种方法是将回调附加到时钟系统。当炸弹被放置时,您添加一个回调,使其在适当的时候调用bomb.explode()。
这里的
callback.function()
可以是任何函数,因为它是一个函数指针。My main use of them has been CALLBACKS: when you need to save information about a function to call later.
Say you're writing Bomberman. 5 seconds after the person drops the bomb, it should explode (call the
explode()
function).Now there's 2 ways to do it. One way is by "probing" all bombs on the screen to see if they're ready to explode in the main loop.
Another way is to attach a callback to your clock system. When a bomb is planted, you add a callback to make it call bomb.explode() when the time is right.
Here
callback.function()
can be any function, because it is a function pointer.就像上面所说的Rich一样,Windows中的函数指针引用一些存储函数的地址是很常见的。
当您在 Windows 平台上使用
C 语言
进行编程时,您基本上会在主内存中加载一些 DLL 文件(使用LoadLibrary
),并且要使用存储在 DLL 中的函数,您需要创建函数指针并指向这些地址(使用GetProcAddress
)。参考文献:
LoadLibrary
GetProcAddress
Like Rich said above, it is very usual for functions pointers in Windows to reference some address that stores function.
When you programming in
C language
on Windows platform you basically load some DLL file in primary memory(usingLoadLibrary
) and to use the functions stored in DLL you need to create functions pointers and point to these address (usingGetProcAddress
).References:
LoadLibrary
GetProcAddress
使用函数指针
根据用户输入动态调用函数。
在这种情况下,通过创建字符串和函数指针的映射。
这样我们就在实际的公司代码中使用了函数指针。
您可以编写“n”个函数并使用此方法调用它们。
输出:
Use of function pointer
To call function dynamically based on user input.
By creating a map of string and function pointer in this case.
This way we have used function pointer in our actual company code.
You may write 'n' number of function and call them using this method.
OUTPUT:
除了这里的其他好的答案之外,还有一个不同的视角:
在 C 中,您仅使用函数指针,而不是(直接)函数。
我的意思是,你可以编写函数,但不能操纵函数。没有您可以使用的函数的运行时表示。你甚至不能调用“函数”。当您编写时:
您实际上说的是“使用指定的参数执行对
my_function
指针的调用”。您正在通过函数指针进行调用。这个函数指针的衰变意味着以下命令相当于前面的函数调用:依此类推(感谢@LuuVinhPhuc) 。
因此,您已经在使用函数指针作为值。显然,您希望为这些值提供变量 - 这就是所有其他提及的用途:多态性/定制(如 qsort 中)、回调、跳转表等。
在 C++ 中,事情有点复杂,因为我们有lambda 表达式,以及带有
operator()
的对象,甚至是std::function
类,但原理仍然基本相同。A different perspective, in addition to other good answers here:
In C, you only use function pointers, not (directly) functions.
I mean, you write functions, but you cant manipulate functions. There's no run-time representation of a function as such which you are able to use. You can't even call "a function". When you write:
what you're actually saying is "perform a call to the
my_function
pointer with the specified argument". You're making a call via a function pointer. This decay to function pointer means that the following commands are equivalent to the previous function call:and so on (thanks @LuuVinhPhuc).
So, you're already using function pointers as values. Obviously you would want to have variables for those values - and here is where all the uses other metion come in: Polymorphism/customization (like in qsort), callbacks, jump tables etc.
In C++ things are a bit more complicated, since we have lambdas, and objects with
operator()
, and even anstd::function
class, but the principle is still mostly the same.我广泛使用函数指针来模拟具有 1 字节操作码的微处理器。 256 个函数指针的数组是实现此目的的自然方法。
I use function pointers extensively, for emulating microprocessors that have 1-byte opcodes. An array of 256 function pointers is the natural way to implement this.
对于面向对象语言,在幕后执行多态调用(我猜这在某种程度上对于 C 也是有效的)。
此外,它们对于在运行时向另一个函数(foo)注入不同的行为非常有用。这使得函数 foo 成为高阶函数。除了灵活性之外,这还使 foo 代码更具可读性,因为它让您可以从中提取“if-else”的额外逻辑。
它在 Python 中支持许多其他有用的东西,比如生成器、闭包等。
For OO languages, to perform polymorphic calls behind the scenes (this is also valid for C up to some point I guess).
Moreover, they're very useful to inject different behaviour to another function (foo) at runtime. That makes function foo higher-order function. Besides it's flexibility, that makes the foo code more readable since it let's you pull that extra logic of "if-else" out of it.
It enables many other useful things in Python like generators, closures etc.
函数指针的一种用途可能是我们可能不想修改调用函数的代码(这意味着调用可能是有条件的,并且在不同的条件下,我们需要进行不同类型的处理)。
这里函数指针非常方便,因为我们不需要修改调用函数的地方的代码。我们只需使用带有适当参数的函数指针来调用该函数。
可以使函数指针有条件地指向不同的函数。 (这可以在初始化阶段的某个地方完成)。此外,如果我们无法修改调用它的代码(假设它是我们无法修改的库 API),则上述模型非常有用。 API 使用函数指针来调用适当的用户定义函数。
One use of function pointer could be where we may not want to modify the code where the function is getting called (meaning thereby the call might be conditional and under different conditions, we need to do different sort of processing).
Here the function pointers are very handy, since we do not need to modify the code at the the place where the function is getting called. We simply call the function using the function pointer with appropriate arguments.
The function pointer can be made to point to different functions conditionally. (This can be done somewhere during initialization phase). Moreover the above model is very helpful, if we are not in position to modify the code where it is getting called (suppose it's a library API we can't modify). The API uses a function pointer for calling the appropriate user defined function.
我将尝试在这里给出一个比较全面的列表:
回调:使用用户提供的代码自定义一些(库)功能。最好的例子是 qsort(),但对于处理事件也很有用(例如单击时调用回调的按钮),或者启动线程所必需的 (
pthread_create()
) .多态性:C++ 类中的 vtable 只是一个函数指针表。 C 程序也可能选择为其某些对象提供 vtable:
Derived
的构造函数随后会将其vtable
成员变量设置为具有派生类的destruct
和实现的全局对象frobnicate
,需要解构struct Base*
的代码只需调用base->vtable->destruct(base)
,这会调用析构函数的正确版本,与base
实际指向哪个派生类无关。如果没有函数指针,多态性将需要用大量的 switch 结构来编码
这很快就会变得相当笨拙。
动态加载代码:当程序将模块加载到内存并尝试调用其代码时,它必须通过函数指针。
我所见过的函数指针的所有用途都完全属于这三大类之一。
I'll try to give a somewhat comprehensive list here:
Callbacks: Customize some (library) functionality with user supplied code. Prime example is
qsort()
, but also useful to handle events (like a button calling a callback when it's clicked), or necessary to start a thread (pthread_create()
).Polymorphism: The vtable in a C++ class is nothing but a table of function pointers. And a C program may also choose to provide a vtable for some of its objects:
The constructor of
Derived
would then set itsvtable
member variable to a global object with the derived's class's implementations ofdestruct
andfrobnicate
, and code that needed to destruct astruct Base*
would simply callbase->vtable->destruct(base)
, which would call the correct version of the destructor, independent of which derived classbase
actually points to.Without function pointers, polymorphism would need to be coded out with an army of switch constructs like
This gets rather unwieldy rather quickly.
Dynamically loaded code: When a program loads a module into memory and tries to call into its code, it must go through a function pointer.
All the uses of function pointers that I've seen fall squarely into one of these three broad classes.
它们增强了代码的重用和模块化,从而使代码更易于维护、可读且不易出错。
使用函数指针:
请注意我们如何使用一个
迭代器
方法来将函数指针传递给它。这个函数指针告诉我们应该如何处理列表中的每个元素。没有函数指针:
如果没有函数指针,您需要在每个
square
、root
和负数
中包含一个迭代器代码>方法。They enhance re-use and modularization of code thus making code more maintainable, readable and less prone to errors.
With function pointers:
Note how we have an
iterator
method that gets passed to it a function pointer. This function pointer tells us what we should do with each elements in the list.Without function pointers:
Without function pointers, you would need to include an iterator in each of the
square
,root
andnegative
methods.大多数示例都归结为回调:调用函数
f()
并传递另一个函数g()
的地址>,并且f()
调用g()
来执行某些特定任务。如果您将f()
传递给h()
的地址,则f()
将回调h() 代替。
基本上,这是一种参数化函数的方法:其行为的某些部分不是硬编码到
f()
中,而是硬编码到回调函数。调用者可以通过传递不同的回调函数来使f()
表现不同。一个经典的例子是 C 标准库中的qsort()
,它将排序标准作为指向比较函数的指针。在 C++ 中,这通常是使用函数对象(也称为函子)来完成的。这些是重载函数调用运算符的对象,因此您可以像调用函数一样调用它们。示例:
这背后的想法是,与函数指针不同,函数对象不仅可以携带算法,还可以携带数据:
另一个优点是,有时内联调用函数对象比通过函数指针进行调用更容易。这就是为什么 C++ 中的排序有时比 C 中的排序更快的原因。
Most examples boil down to callbacks: You call a function
f()
passing the address of another functiong()
, andf()
callsg()
for some specific task. If you passf()
the address ofh()
instead, thenf()
will call backh()
instead.Basically, this is a way to parametrize a function: Some part of its behavior is not hard-coded into
f()
, but into the callback function. Callers can makef()
behave differently by passing different callback functions. A classic isqsort()
from the C standard library that takes its sorting criterion as a pointer to a comparison function.In C++, this is often done using function objects (also called functors). These are objects that overload the function call operator, so you can call them as if they were a function. Example:
The idea behind this is that, unlike a function pointer, a function object can carry not only an algorithm, but also data:
Another advantage is that it is sometimes easier to inline calls to function objects than calls through function pointers. This is a reason why sorting in C++ is sometimes faster than sorting in C.
好吧,我通常在 跳转表 中(专业地)使用它们(另请参阅这个 StackOverflow 问题)。
跳转表通常(但不限于)用在有限状态机中,使其成为数据驱动的。 而不是嵌套的 switch/case
您可以创建一个函数指针的二维数组,然后调用handleEvent[state][event],
Well, I generally use them (professionally) in jump tables (see also this StackOverflow question).
Jump tables are commonly (but not exclusively) used in finite state machines to make them data driven. Instead of nested switch/case
you can make a 2d array of function pointers and just call
handleEvent[state][event]
示例:
模式(如策略、观察者)
Examples:
patterns (like Strategy, Observer)
函数指针有用性的“经典”示例是 C 库 qsort() 函数,它实现了快速排序。为了对用户可能提出的任何和所有数据结构通用,它需要几个指向可排序数据的空指针和一个指向知道如何比较这些数据结构的两个元素的函数的指针。这使我们能够为作业创建选择的函数,实际上甚至允许在运行时选择比较函数,例如升序或降序排序。
The "classic" example for the usefulness of function pointers is the C library
qsort()
function, which implements a Quick Sort. In order to be universal for any and all data structures the user may come up with, it takes a couple of void pointers to sortable data and a pointer to a function that knows how to compare two elements of these data structures. This allows us to create our function of choice for the job, and in fact even allows for choosing the comparison function at run time, e.g. for sorting ascending or descending.同意以上所有内容,另外......
当您在运行时动态加载 dll 时,您将需要函数指针来调用函数。
Agree with all of the above, plus....
When you load a dll dynamically at runtime you'll need function pointers to call the functions.
在 C 语言中,经典的用法是 qsort 函数,其中第四个参数是指向用于执行排序内排序的函数的指针。在 C++ 中,人们倾向于使用函子(看起来像函数的对象)来完成这类事情。
In C, the classic use is the qsort function, where the fourth parameter is pointer to a function to use to perform the ordering within the sort. In C++, one would tend to use functors (objects that look like functions) for this kind of thing.
我要在这里逆流而上。
在C中,函数指针是实现定制的唯一方法,因为没有OO。
在 C++ 中,您可以使用函数指针或函子(函数对象)来获得相同的结果。
由于函子的对象性质,与原始函数指针相比,函子具有许多优点,特别是:
operator()
的多个重载lambda
和bind
)我个人更喜欢函子而不是函数指针(尽管有样板代码),主要是因为函数指针的语法很容易变得毛茸茸的(来自函数指针教程):这是
我唯一一次看到在函子不能使用的地方使用函数指针是在 Boost.Spirit 中。他们完全滥用了语法来将任意数量的参数作为单个模板参数传递。
但由于可变参数模板和 lambda 即将到来,我不确定我们是否会在纯 C++ 代码中长期使用函数指针。
I am going to go against the current here.
In C, function pointers are the only way to implement customization, because there is no OO.
In C++, you can use either function pointers or functors (function objects) for the same result.
The functors have a number of advantages over raw function pointers, due to their object nature, notably:
operator()
lambda
andbind
)I personally prefer functors to function pointers (despite the boilerplate code), mostly because the syntax for function pointers can easily get hairy (from the Function Pointer Tutorial):
The only time I have ever seen function pointers used where functors could not was in Boost.Spirit. They have utterly abused the syntax to pass an arbitrary number of parameters as a single template parameter.
But since variadic templates and lambdas are around the corner, I am not sure we will use function pointers in pure C++ code for long now.
我最近使用函数指针来创建抽象层。
我有一个用纯 C 编写的程序,可以在嵌入式系统上运行。它支持多种硬件变体。根据我运行的硬件,它需要调用某些函数的不同版本。
在初始化时,程序会找出它正在运行的硬件并填充函数指针。程序中的所有高级例程仅调用指针引用的函数。我可以添加对新硬件变体的支持,而无需触及更高级别的例程。
我曾经使用 switch/case 语句来选择正确的函数版本,但随着程序发展到支持越来越多的硬件变体,这变得不切实际。我不得不到处添加案例陈述。
我还尝试了中间函数层来确定要使用哪个函数,但它们没有多大帮助。每当我们添加新的变体时,我仍然必须在多个地方更新 case 语句。使用函数指针,我只需更改初始化函数。
I used function pointers recently to create an abstraction layer.
I have a program written in pure C that runs on embedded systems. It supports multiple hardware variants. Depending on the hardware I am running on, it needs to call different versions of some functions.
At initialization time, the program figures out what hardware it is running on and populates the function pointers. All of the higher-level routines in the program just call the functions referenced by pointers. I can add support for new hardware variants without touching the higher-level routines.
I used to use switch/case statements to select the proper function versions, but this became impractical as the program grew to support more and more hardware variants. I had to add case statements all over the place.
I also tried intermediate function layers to figure out which function to use, but they didn't help much. I still had to update case statements in multiple places whenever we added a new variant. With the function pointers, I only have to change the initialization function.
在 C 语言中可以使用函数指针来创建一个用于编程的接口。根据运行时所需的特定功能,可以为函数指针分配不同的实现。
Function pointers can be used in C to create an interface against which to program. Depending on the specific functionality that is needed at runtime, a different implementation can be assigned to the function pointer.