其他语言

本类阅读TOP10

·基于Solaris 开发环境的整体构思
·使用AutoMake轻松生成Makefile
·BCB数据库图像保存技术
·GNU中的Makefile
·射频芯片nRF401天线设计的分析
·iframe 的自适应高度
·BCB之Socket通信
·软件企业如何实施CMM
·入门系列--OpenGL最简单的入门
·WIN95中日志钩子(JournalRecord Hook)的使用

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
Ask the C++ Pro 10-Minute Solution

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

Ask the C++ Pro 10-Minute Solution

Declaring Function Pointers and Implementing Callbacks
By Danny Kalev

Programmers often need to implement callbacks. I will discuss the fundamentals of function pointers and show how to use them to implement callbacks. Notice that this article focuses on ordinary functions, not class member functions, which rely on substantially different syntactic and semantic rules (pointers to class members were discussed in a previous 10-Minute Solution).

Declaring a Function Pointer
A callback function is one that is not invoked explicitly by the programmer; rather the responsibility for its invocation is delegated to another function that receives the callback function's address. To implement a callback, you need to define an appropriate function pointer first. Although the syntax is a bit arcane, if you're familiar with function declarations in general, you will notice that a function pointer declaration is very similar to a function declaration. Consider the following example:

   void f(); // a function prototype
   

It declares a function f() that takes no arguments and returns void. A pointer to such a function has the following type:

  void (*) ();
 

Let's parse it. The asterisk in the leftmost parentheses is the nucleus of a function pointer declaration. Two additional elements are the function's return type, which appears on the left and is 'void' in our example, and a parameter list enclosed in the rightmost parentheses. In our case, the parameter list is empty because f() takes no arguments. Note that we didn't create a pointer variable yet—we only declared the type of such a variable. We can use this type to create a typedef name, or in a sizeof expression:

  // get the size of a function pointer
  unsigned psize = sizeof (void (*) ()); 
  

// declare a typedef for a function pointer typedef void (*pfv) ();

pfv is a synonym for "a pointer to a function that takes no arguments and returns void". We can use this typedef name to hide the cumbersome syntax of function pointers.

A pointer variable, of course, has a name. Here is an example of such a pointer:

  void (*p) (); // p is a pointer to a function 

p is a pointer to a function that takes no arguments and returns void. The name of a pointer variable appears on the right of the asterisk, inside the parentheses. We can now assign a value to p. A value is simply a name of a function that has a matching signature (parameter list) and return type. For example:

  void func() 
  {
    /* do something */
  } 
  p = func; 

You can assign a different value to p as long as it's the address of a function with the same signature and return type. A function's name is not a part of its type, though.

Passing an Address of a Callback Function to Its Caller
Now we can pass p to another function, caller(), which will call the function to which p points (the callee) without knowing its name:

    void caller(void(*ptr)())
  {
    ptr(); /* call the function to which ptr points */ 
  }
  void func();
  int main()
  {
    p = func; 
    caller(p); /* pass address of func to caller */
  }

If you assign a different function to p, caller() will invoke that function. The assignment can take place at runtime, which enables you to implement dynamic binding.

Calling Conventions
Up until now, we've discussed function pointers and callbacks without discussing compiler-specific conventions that aren't defined by ANSI C/C++. Many compilers have several calling conventions. For example, in Visual C++ you can precede __cdecl, __stdcall or __pascal to a function's type to indicate its calling convention (__cdecl is the default). C++ Builder also supports the __fastcall calling convention. The calling convention affects the compiler-generated name of a given function (i.e., name mangling), the order in which arguments are passed (right to left or left to right), stack cleanup responsibility (by the caller or the callee), and the mechanism for argument passing (stack, CPU registers, etc.).

It's important to note that the calling convention is an integral part of a function's type; you can't assign an address of a function to a pointer with an incompatible calling convention. For example:

  // callee is a function that takes int and returns int
  __stdcall int callee(int);  

  // caller is a function that takes a function pointer
  void caller( __cdecl int(*ptr)(int));  

  // illegal attempt to store the address of callee in p
  __cdecl int(*p)(int) = callee; // error

p and callee() have incompatible types because they have different calling conventions. Therefore, you can't assign callee's address to the pointer p, although both have the same return value and parameter list.




相关文章

相关软件