A
function pointer(Pointer to Function/Subroutine Pointer/Procedure Pointer) is nothing else than a variable (stores the address of
a function within executable memory) that can later be called through
that function pointer. For instance, every time you need a particular
behavior such as drawing a line, instead of writing out a bunch of code,
all you need to do is call the function. But sometimes you would like
to choose different behaviors at different times in essentially the same
piece of code.
Function Pointer can be used to replace switch/if-statements, and to realize late-binding. Late binding refers to deciding the proper function during runtime instead of compile time.
Functions in C are actually just pointers to a spot in the program where some code exists. Just like you've been creating pointers to structs, strings, and arrays, you can point a pointer at a function too. The main use for this is to pass "callbacks" to other functions, or to simulate classes and objects. This is useful because functions encapsulate behavior.
// define a function pointer
int (*ptr2Function)(int, char);
In this example, ptr2Function is a pointer to a function taking two argument, an integer and a character which returns int. It's as if you're declaring a function called "*ptr2Function", which takes an int and a char and returns int; now, if *ptr2Function is a function, then ptr2Function must be a pointer to a function. (Similarly, a declaration like int *x can be read as *x is an int, so x must be a pointer to an int.)
Now lets start with reading part that how to read any function pointer declaration having more stars :
Functions in C are actually just pointers to a spot in the program where some code exists. Just like you've been creating pointers to structs, strings, and arrays, you can point a pointer at a function too. The main use for this is to pass "callbacks" to other functions, or to simulate classes and objects. This is useful because functions encapsulate behavior.
// define a function pointer
int (*ptr2Function)(int, char);
In this example, ptr2Function is a pointer to a function taking two argument, an integer and a character which returns int. It's as if you're declaring a function called "*ptr2Function", which takes an int and a char and returns int; now, if *ptr2Function is a function, then ptr2Function must be a pointer to a function. (Similarly, a declaration like int *x can be read as *x is an int, so x must be a pointer to an int.)
Now lets start with reading part that how to read any function pointer declaration having more stars :
void *(*ptr2Function)(int *);
Here, the key is to read inside-out; notice that the innermost element of the expression is *ptr2Function, and that otherwise it looks like a normal function declaration. *ptr2Function should refer to a function that returns a void * and takes an int *. Consequently, ptr2Function is a pointer to just such a function.
Here, the key is to read inside-out; notice that the innermost element of the expression is *ptr2Function, and that otherwise it looks like a normal function declaration. *ptr2Function should refer to a function that returns a void * and takes an int *. Consequently, ptr2Function is a pointer to just such a function.
Initializing Function Pointers
To initialize a function pointer, you must give it the address of a function in your program. The syntax is like any other variable:
#include <stdio.h>
void my_int_func(int x)
{
printf( "%d\n", x );
}
To initialize a function pointer, you must give it the address of a function in your program. The syntax is like any other variable:
#include <stdio.h>
void my_int_func(int x)
{
printf( "%d\n", x );
}
int main()
{
void (*ptr2Function)(int);
/* the ampersand is actually optional */
ptr2Function = &my_int_func;
return 0;
}
Using a Function Pointer
To call the function pointed to by a function pointer, you treat the function pointer as though it were the name of the function you wish to call. The act of calling it performs the dereference; there's no need to do it yourself:
#include <stdio.h>
void my_int_func(int x)
{
printf( "%d\n", x );
}
int main()
{
void (*ptr2Function)(int);
ptr2Function = &my_int_func;
/* call my_int_func (note that you do not need to write (*ptr2Function)(2) ) */
ptr2Function( 2 );
/* but if you want to, you may */
(*ptr2Function)( 2 );
return 0;
}
Output :
2
2
Note that function pointer syntax is flexible; it can either look like most other uses of pointers, with & and *, or you may omit that part of syntax. This is similar to how arrays are treated, where a bare array decays to a pointer, but you may also prefix the array with & to request its address.
Pointers to functions are interesting when you pass them to other functions. A function that takes function pointers says, in effect, "Part of what I do can be customized. Give me a pointer to a function, and I'll call it when that part of the job needs to be done. That function can do its part for me." This is known as a "callback." It's used a lot in graphical user interface libraries, in which the style of a display is built into the library but the contents of the display are part of the application.
As a simpler example, say you have an array of character pointers (char*s), and you want to sort it by the value of the strings the character pointers point to. The standard qsort() function uses function pointers to perform that task. qsort() takes four arguments
1. a pointer to the beginning of the array,
2. the number of elements in the array,
3. the size of each array element, and
4. a comparison function.
and returns an int.
The comparison function takes two arguments, each a pointer to an element. The function returns 0 if the pointed-to elements compare equal, some negative value if the first element is less than the second, and some positive value if the first element is greater than the second. A comparison function for integers might look like this:
int icmp( const int *p1, const int *p2 )
{
return *p1 - *p2;
}
The sorting algorithm is part of qsort(). So is the exchange algorithm; it just copies bytes, possibly by calling memcpy() or memmove(). qsort() doesn't know what it's sorting, so it can't know how to compare them. That part is provided by the function pointer.
You can't use strcmp() as the comparison function for this example, for two reasons. The first reason is that strcmp()'s type is wrong; more on that a little later. The second reason is that it won't work. strcmp() takes two pointers to char and treats them as the first characters of two strings. The example deals with an array of character pointers (char*s), so the comparison function must take two pointers to character pointers (char*s). In this case, the following code might be an example of a good comparison function:
int strpcmp( const void *p1, const void *p2 )
{
char * const *sp1 = (char * const *) p1;
char * const *sp2 = (char * const *) p2;
return strcmp( *sp1, *sp2 );
}
The call to qsort() might look something like this:
qsort( array, numElements, sizeof( char * ), pf2 );
qsort() will call strpcmp() every time it needs to compare two character pointers (char*s).
Why can't strcmp() be passed to qsort(), and why were the arguments of strpcmp() what they were?
A function pointer's type depends on the return type of the pointed-to function, as well as the number and types of all its arguments. qsort() expects a function that takes two constant void pointers:
void qsort( void *base,
size_t numElements,
size_t sizeOfElement,
int (*compFunct)( const void *, const void *) );
Because qsort() doesn't really know what it's sorting, it uses a void pointer in its argument (base) and in the arguments to the comparison function. qsort()'s void* argument is easy; any pointer can be converted to a void* without even needing a cast. The function pointer is harder.
For an array of character arrays, strcmp() would have the right algorithm but the wrong argument types. The simplest, safest way to handle this situation is to pass a function that takes the right argument types for qsort() and then casts them to the right argument types. That's what strpcmp() does.
If you have a function that takes a char*, and you know that a char* and a void* are the same in every environment your program might ever work in, you might cast the function pointer, rather than the pointed- to function's arguments, in this way:
char table[ NUM_ELEMENTS ][ ELEMENT_SIZE ];
/* ... */
/* passing strcmp() to qsort for array of array of char */
qsort( table, NUM_ELEMENTS, ELEMENT_SIZE,
( int (*)( const void *, const void * ) ) strcmp );
Casting the arguments and casting the function pointer both can be error prone. In practice, casting the function pointer is more dangerous.
The basic problem here is using void* when you have a pointer to an unknown type. C++ programs sometime solve this problem with templates.
Example :
The following code in C demonstrates the use of callbacks to display two numbers.
#include <stdio.h>
#include <stdlib.h>
/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
printf("%d and %d\n", numberSource(), numberSource());
}
/* A possible callback */
int overNineThousand(void) {
return (rand() % 1000) + 9001;
}
/* Another possible callback. */
int meaningOfLife(void) {
return 42;
}
/* Here we call PrintTwoNumbers() with three different callbacks. */
int main(void) {
PrintTwoNumbers(&rand);
PrintTwoNumbers(&overNineThousand);
PrintTwoNumbers(&meaningOfLife);
return 0;
}
Output :
846930886 and 1804289383
9916 and 9778
42 and 42
Note that function pointer syntax is flexible; it can either look like most other uses of pointers, with & and *, or you may omit that part of syntax. This is similar to how arrays are treated, where a bare array decays to a pointer, but you may also prefix the array with & to request its address.
Pointers to functions are interesting when you pass them to other functions. A function that takes function pointers says, in effect, "Part of what I do can be customized. Give me a pointer to a function, and I'll call it when that part of the job needs to be done. That function can do its part for me." This is known as a "callback." It's used a lot in graphical user interface libraries, in which the style of a display is built into the library but the contents of the display are part of the application.
As a simpler example, say you have an array of character pointers (char*s), and you want to sort it by the value of the strings the character pointers point to. The standard qsort() function uses function pointers to perform that task. qsort() takes four arguments
1. a pointer to the beginning of the array,
2. the number of elements in the array,
3. the size of each array element, and
4. a comparison function.
and returns an int.
The comparison function takes two arguments, each a pointer to an element. The function returns 0 if the pointed-to elements compare equal, some negative value if the first element is less than the second, and some positive value if the first element is greater than the second. A comparison function for integers might look like this:
int icmp( const int *p1, const int *p2 )
{
return *p1 - *p2;
}
The sorting algorithm is part of qsort(). So is the exchange algorithm; it just copies bytes, possibly by calling memcpy() or memmove(). qsort() doesn't know what it's sorting, so it can't know how to compare them. That part is provided by the function pointer.
You can't use strcmp() as the comparison function for this example, for two reasons. The first reason is that strcmp()'s type is wrong; more on that a little later. The second reason is that it won't work. strcmp() takes two pointers to char and treats them as the first characters of two strings. The example deals with an array of character pointers (char*s), so the comparison function must take two pointers to character pointers (char*s). In this case, the following code might be an example of a good comparison function:
int strpcmp( const void *p1, const void *p2 )
{
char * const *sp1 = (char * const *) p1;
char * const *sp2 = (char * const *) p2;
return strcmp( *sp1, *sp2 );
}
The call to qsort() might look something like this:
qsort( array, numElements, sizeof( char * ), pf2 );
qsort() will call strpcmp() every time it needs to compare two character pointers (char*s).
Why can't strcmp() be passed to qsort(), and why were the arguments of strpcmp() what they were?
A function pointer's type depends on the return type of the pointed-to function, as well as the number and types of all its arguments. qsort() expects a function that takes two constant void pointers:
void qsort( void *base,
size_t numElements,
size_t sizeOfElement,
int (*compFunct)( const void *, const void *) );
Because qsort() doesn't really know what it's sorting, it uses a void pointer in its argument (base) and in the arguments to the comparison function. qsort()'s void* argument is easy; any pointer can be converted to a void* without even needing a cast. The function pointer is harder.
For an array of character arrays, strcmp() would have the right algorithm but the wrong argument types. The simplest, safest way to handle this situation is to pass a function that takes the right argument types for qsort() and then casts them to the right argument types. That's what strpcmp() does.
If you have a function that takes a char*, and you know that a char* and a void* are the same in every environment your program might ever work in, you might cast the function pointer, rather than the pointed- to function's arguments, in this way:
char table[ NUM_ELEMENTS ][ ELEMENT_SIZE ];
/* ... */
/* passing strcmp() to qsort for array of array of char */
qsort( table, NUM_ELEMENTS, ELEMENT_SIZE,
( int (*)( const void *, const void * ) ) strcmp );
Casting the arguments and casting the function pointer both can be error prone. In practice, casting the function pointer is more dangerous.
The basic problem here is using void* when you have a pointer to an unknown type. C++ programs sometime solve this problem with templates.
Example :
The following code in C demonstrates the use of callbacks to display two numbers.
#include <stdio.h>
#include <stdlib.h>
/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
printf("%d and %d\n", numberSource(), numberSource());
}
/* A possible callback */
int overNineThousand(void) {
return (rand() % 1000) + 9001;
}
/* Another possible callback. */
int meaningOfLife(void) {
return 42;
}
/* Here we call PrintTwoNumbers() with three different callbacks. */
int main(void) {
PrintTwoNumbers(&rand);
PrintTwoNumbers(&overNineThousand);
PrintTwoNumbers(&meaningOfLife);
return 0;
}
Output :
846930886 and 1804289383
9916 and 9778
42 and 42
Callback Function :
"I don't call it by myself, but the system (or some others) will call it". That's callback.
A
function that is called through a function pointer. If you pass the
pointer (address) of a function as an argument to another, when that
pointer is used to call the function it points to it is said that a call
back is made.
According to Wikipedia "In computer programming way, callback is a piece of executable code that is
passed as an argument to other code, which is expected to call back
(execute) the argument at some convenient time.The invocation may be immediate as in a synchronous callback, or it might happen at later time as in an asynchronous callback. In all cases, the intention is to specify a function or subroutine as an entity that is, depending on the language, more or less similar to a variable."
A practical example of callback:
Windows event processing:
virtually all windows programs set up an event loop, that makes the program respond to particular events (eg. button presses, selecting a check box, window getting focus) by calling a function. The handy thing is that the programmer can specify what function gets called when (say) a particular button is pressed, even though it is not possible to specify when the button will be pressed. The function that is called is referred to as a callback.
A practical example of callback:
Windows event processing:
virtually all windows programs set up an event loop, that makes the program respond to particular events (eg. button presses, selecting a check box, window getting focus) by calling a function. The handy thing is that the programmer can specify what function gets called when (say) a particular button is pressed, even though it is not possible to specify when the button will be pressed. The function that is called is referred to as a callback.
No comments:
Post a Comment