A callback is a function that you supply, which will be called sometime later on. Different programming languages provide different ways of specifying callback functions.
Callbacks are useful in many scenarios, but they generally fall into one of two categories: synchronous callbacks and asynchronous callbacks.
Synchronous callbacks are often used when some generic code needs to know how to perform some non-generic action, so you supply a function that knows how to perform that action. Effectively, you use a callback function to customize an existing function so that it does what you need it to do.
For example, the qsort function in C can sort any type of data, but it has no idea what type of data it’s supposed to be sorting, and has no idea how to compare two objects of that type. So, you, the user of the qsort function, must supply a callback function that knows how to compare two objects of the type you’re going to sort, and qsort calls your comparison function every time it needs to perform a comparison of two objects. (You can learn more about the qsort function and specifying callback comparison functions here.)
The scenario is synchronous because all the calls to your callback function will take place before the qsort function returns control to you.
Asynchronous callbacks are often used when you need to perform some action when an event occurs, so you supply a callback function that you want called whenever a specific event occurs. The callback functions are often referred to as event handlers or just handlers.
An event might be when a long I/O operation completes, when the user moves the mouse, when the user clicks a mouse button, when the user presses a keyboard key, when a sound is detected, when a timer expires, when a communication device receives some data, when some exceptional condition occurs, when a device reports that it’s ready, and the list goes on and on.
A simple example is the atexit function in C. You supply this function with a callback function that you want to have called when the program terminates normally (either by completing the main function or through a call to the exit function). You can call atexit multiple times, specifying different callback functions each time. When the program terminates normally (i.e., the event you’re interested in occurs), each of your callback functions (i.e., your exit event handlers) will be called.
Asynchronous callbacks are fundamental to event-driven programming. Virtually all GUI programs are event-driven, and embedded systems are typically event driven as well. The callbacks are asynchronous because, after you provide the callback function, control is (typically) returned immediately to you, and the callback function will get called one or more times in the future, when the event you’re interested in occurs (if it ever occurs).