程序员常常需要实现回调。本文将讨论函数指针的基本原则并说明如何使用函数指针实现回调。注意这里针对的是普通的函数,不包括完全依赖于不同语法和语义规则的类成员函数(类成员指针将在另文中讨论)。
声明函数指针
回调函数是一个程序员不能显式调用的函数;通过将回调函数的地址传给调用者从而实现调用。要实现回调,必须首先定义函数指针。尽管定义的语法有点不可思议,但如果你熟悉函数声明的一般方法,便会发现函数指针的声明与函数声明非常类似。请看下面的例子:
void f();// 函数原型
上面的语句声明了一个函数,没有输入参数并返回void。那么函数指针的声明方法如下:
void (*) ();
让我们来分析一下,左边圆括弧中的星号是函数指针声明的关键。另外两个元素是函数的返回类型(void)和由边圆括弧中的入口参数(本例中参数是空)。注意本例中还没有创建指针变量-只是声明了变量类型。目前可以用这个变量类型来创建类型定义名及用sizeof表达式获得函数指针的大小:
// 获得函数指针的大小
unsigned psize = sizeof (void (*) ());
// 为函数指针声明类型定义
typedef void (*pfv) ();
pfv是一个函数指针,它指向的函数没有输入参数,返回类行为void。使用这个类型定义名可以隐藏复杂的函数指针语法。
指针变量应该有一个变量名:
void (*p) (); //p是指向某函数的指针
p是指向某函数的指针,该函数无输入参数,返回值的类型为void。左边圆括弧里星号后的就是指针变量名。有了指针变量便可以赋值,值的内容是署名匹配的函数名和返回类型。例如:
void func()
{
/* do something */
}
p = func;
p的赋值可以不同,但一定要是函数的地址,并且署名和返回类型相同。
传递回调函数的地址给调用者
现在可以将p传递给另一个函数(调用者)- caller(),它将调用p指向的函数,而此函数名是未知的:
void caller(void(*ptr)())
{
ptr(); /* 调用ptr指向的函数 */
}
void func();
int main()
{
p = func;
caller(p); /* 传递函数地址到调用者 */
}
如果赋了不同的值给p(不同函数地址),那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
调用规范
到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++ Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。
将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:
// 被调用函数是以int为参数,以int为返回值
__stdcall int callee(int);
// 调用函数以函数指针为参数
void caller( __cdecl int(*ptr)(int));
// 在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; // 出错
指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列。
分享到:
相关推荐
回调函数在C语言中是一种非常重要的编程机制,它允许我们将一个函数的地址作为参数传递给另一个函数,由这个函数在适当的时候调用我们传入的函数。这种模式在处理异步事件、信号处理、排序算法以及其他需要在特定...
在Microsoft Foundation Classes (MFC) 中,回调函数是一种特殊类型的函数,它允许用户代码与库或操作系统进行交互,尤其是在处理异步事件时。回调函数通常作为参数传递给其他函数,以便在特定事件发生时调用。在MFC...
在C++ Builder中,回调函数是一种关键的设计模式,用于在动态链接库(DLL)中调用主程序中的特定函数。回调函数允许DLL与主程序进行通信,传递数据或执行特定操作。 首先,让我们理解什么是回调函数。回调函数是...
标题中的“PB 回调函数,多线程”指的是在编程中使用ProtoBuf(Protocol Buffers,简称PB)实现回调函数来处理多线程应用程序。ProtoBuf是Google开发的一种数据序列化协议,常用于结构化数据的存储和交换,它可以...
在Delphi编程环境中,DLL的使用尤为常见,尤其是涉及到回调函数时。回调函数允许DLL将控制权返回给调用者,使得调用者能够处理特定的事件或任务。本篇文章将深入探讨Delphi中DLL的回调函数及其应用。 首先,我们...
回调函数在编程中是一种强大的设计模式,特别是在C#这样的面向对象语言中,它允许你在方法执行完毕后调用另一个特定的函数。回调函数通常用于异步编程,事件处理或者作为参数传递,使得代码更加灵活和可扩展。接下来...
在编程领域,回调函数是一种非常重要的设计模式,它允许我们将一个方法作为参数传递给另一个方法,在特定条件下由被调用的方法执行。在C#中,回调函数同样被广泛使用,尤其是在异步编程、事件处理和自定义算法中。本...
在Java编程中,回调函数是一种设计模式,它允许一个对象在另一个对象执行特定操作后接收通知或进行处理。这种机制通常用于事件驱动编程或者异步编程中,使得代码能够响应某些特定事件的发生。在给定的场景中,我们...
在编程领域,回调函数是一种设计模式,它允许我们定义一个函数,这个函数可以在另一个函数执行完毕后被调用。在Android开发中,回调函数扮演着至关重要的角色,尤其是在处理异步操作、事件监听以及用户交互时。本...
回调函数是DLL中一个特殊的概念,它允许DLL将控制权交还给调用者,让调用者执行特定的代码。这种机制在处理异步操作、事件处理或自定义数据处理时非常有用。本文将深入探讨Delphi中DLL的回调函数的使用及其相关知识...
本示例"动态库回调函数示例"旨在演示如何在 VC++6.0 下创建和使用 DLL,特别是在 DLL 中定义回调函数。回调函数是一种编程技术,允许 DLL 将控制权交还给调用它的应用程序,以便在特定事件发生时执行自定义操作。 ...
在C语言中一般用typedef来为回调函数定义别名(参数名)。 别名通过宏定义typedef来实现,不是简单的宏替换。可以用作同时声明指针型的多个对象。 比如: 代码如下:char *pa,pb;//pa是一个char型指针,但pb是一个...
【osg回调函数的使用】 OpenSceneGraph(OSG)是一个强大的3D图形库,它提供了丰富的功能来构建复杂的三维场景。在OSG中,回调函数是实现用户自定义行为的关键工具,它们允许开发者在特定事件发生时执行特定的代码...
回调函数则是编程中一种常见的设计模式,它允许函数将控制权返回给调用者,使得调用者可以在适当的时候执行特定的处理逻辑。在VC++中,将回调函数实现在DLL中,可以提供更加灵活的跨模块通信方式。 首先,我们需要...
lwip的回调函数学习笔记与相关函数释疑 lwip 是一个轻量级的TCP/IP协议栈,广泛应用于嵌入式系统中。在lwip中,回调函数是一种重要的机制,用于处理网络事件和数据传输。本文将详细介绍lwip的回调函数学习笔记与...
在C#编程中,回调函数是一种非常重要的设计模式,它允许我们传递一个方法作为参数到另一个方法中,以便在特定事件发生或者特定条件满足时执行。这种机制使得代码具有高度的灵活性和可扩展性,特别是在处理异步操作、...
在串口通信中,我们可以设置一个回调函数来处理接收到的数据。首先定义一个函数,例如: ```matlab function serialCallback(obj, event) data = obj.InputBuffer; % 在这里处理接收到的数据 end ``` 然后,...
网上的回调函数都是API例子,学习函数指针倒是不错,可是很难让初学者立即应用。常见的情况是辅线程完成某事件后需要“通知”主界面,比如常见的进度条——线程中完成一定的进度后即通知主界面显示到一定的刻度。本...
### 回调函数被连续执行两次或多次的原因 在编程领域,回调函数是一种常见的编程模式,它允许将函数作为参数传递给另一个函数,并在适当的时机由后者调用。这种模式非常有用,尤其是在处理异步操作时。然而,在某些...
### C++中的回调函数及其应用 #### 回调函数的概念及定义 回调函数是一种特殊的函数,在C++编程中被广泛使用。回调函数的基本思想是将一个函数作为参数传递给另一个函数,然后在适当的时机调用这个传递进来的函数...