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.

 
Other 10-Minute Solutions
 How to Change the Mouse Pointer without Flicker
 Setting Full Row Selection in ListView Control
 Automating Type Conversions with stringstream Objects
 Improving Memory Reallocation with Vectors
 How to Use <fstream> Classes for File I/O
 Casting About for Safe Typecasting
 Overloading Operator + the Right Way
 How to Create Persistent Objects
 Making Linked Lists More User-Friendly
 Preventing Glitches in Signal Processing
 Forcing Object Allocation on the Free-store
 Using String-Based Data Validation
 Implementing the 'Resource Acquisition Is Initialization' Idiom
 Simple Locks for Data Files
 Template Specializations
 Exception Handling
 Using Bit Fields in Data Optimization
 Using the Transform() Algorithm to Change a String's Case
 Use RTTI for Dynamic Type Identification
 Choosing the Right swap () Implementation
 Take Charge and Initialize Your Own Data
 Share Data Among Objects Using the Monostate Design Pattern
 String Manipulation Made Easy with std::string Algorithms
 Using typedef to Curb Miscreant Code
 Managing Objects' Construction Order
 Bitwise Operators: Combining Efficiency and Ease of Use
 Use Function Adapters to Extend Generic Algorithms' Usage
 Simplify Callback Dispatching with Enumerated Indexes
 Streamline Your Bulk I/O Operations with Stream Iterators
 Optimize Your Member Layout
 Preserve Code Safety with Conversion Operators
 Modify Your Base Class Interface in Derived Classes
 Tackle Common Programming Tasks Using the New <tuple> Library
 Use Local Classes for Proper Cleanup in Exception-enabled Apps
 Use multimap to Create Associative Containers with Duplicate Keys
 Enforcing Compile-time Constraints
 Facilitate Directory Operations with the <dirent.h> and <dir.h> Libraries
 Spruce Up Your Built-in Arrays
 Target 32- and 64-bit Platforms Together with a Few Simple Datatype Changes
 Restrict Object Allocation to Specific Memory Types
 Use the Pimpl Idiom to Reduce Compilation Time and Enhance Encapsulation
 Automate Resource Management with shared_ptr
 The Quick and Dirty Way to Add
 Pointing to Class Members
 Detecting Keystrokes While Your Application is Busy
 Linked Lists
 Programming the System Tray
 Create a "Universal" DLL
 Convert Path to Long Path Name
 Constructing an Object at a Pre-Determined Memory Position
 Declaring Classes and Member Functions in a Namespace
 Using the auto_ptr Class Template to Facilitate Dynamic Memory Management
 Using the random_shuffle() Algorithm to Randomize a Sequence of Elements
 Defining a Function Object
 Implementing the Singleton Design Pattern
 Declaring Function Pointers and Implementing Callbacks
 Overloading Operator << for a User-Defined Type
 Implementing a Stopwatch Class for Performance Measurements
 Creating and Accessing Environment Variables
 Executing an Object's Member Function in a Separate Thread
 Creating Heterogeneous Containers
 Overriding New and Delete
 Time and Date Manipulation
  Defining Functions with a Variable Argument List
 Optimize Abstract Operations with Function Templates




Sponsored Links


Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map
Jupiterweb networks

internet.comearthweb.comDevx.comClickZ

Search Jupiterweb:

Jupitermedia Corporation has four divisions:
JupiterWeb, JupiterResearch, JupiterEvents, and JupiterImages

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers