I had some experience lately with function pointers in C.
So going on with the tradition of answering your own questions, I decided to make a small summary of the very basics, for those who need a quick dive-in to the subject.
转载于:https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work
Let's start with a basic function which we will be pointing to:
int addInt(int n, int m) {
return n+m;
}
First thing, let's define a pointer to a function which receives 2 int
s and returns an int
:
int (*functionPtr)(int,int);
Now we can safely point to our function:
functionPtr = &addInt;
Now that we have a pointer to the function, let's use it:
int sum = (*functionPtr)(2, 3); // sum == 5
Passing the pointer to another function is basically the same:
int add2to3(int (*functionPtr)(int, int)) {
return (*functionPtr)(2, 3);
}
We can use function pointers in return values as well (try to keep up, it gets messy):
// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int
int (*functionFactory(int n))(int, int) {
printf("Got parameter %d", n);
int (*functionPtr)(int,int) = &addInt;
return functionPtr;
}
But it's much nicer to use a typedef
:
typedef int (*myFuncDef)(int, int);
// note that the typedef name is indeed myFuncDef
myFuncDef functionFactory(int n) {
printf("Got parameter %d", n);
myFuncDef functionPtr = &addInt;
return functionPtr;
}
One of my favorite uses for function pointers is as cheap and easy iterators -
#include <stdio.h>
#define MAX_COLORS 256
typedef struct {
char* name;
int red;
int green;
int blue;
} Color;
Color Colors[MAX_COLORS];
void eachColor (void (*fp)(Color *c)) {
int i;
for (i=0; i<MAX_COLORS; i++)
(*fp)(&Colors[i]);
}
void printColor(Color* c) {
if (c->name)
printf("%s = %i,%i,%i\n", c->name, c->red, c->green, c->blue);
}
int main() {
Colors[0].name="red";
Colors[0].red=255;
Colors[1].name="blue";
Colors[1].blue=255;
Colors[2].name="black";
eachColor(printColor);
}
Function pointers in C can be used to perform object-oriented programming in C.
For example, the following lines is written in C:
String s1 = newString();
s1->set(s1, "hello");
Yes, the ->
and the lack of a new
operator is a dead give away, but it sure seems to imply that we're setting the text of some String
class to be "hello"
.
By using function pointers, it is possible to emulate methods in C.
How is this accomplished?
The String
class is actually a struct
with a bunch of function pointers which act as a way to simulate methods. The following is a partial declaration of the String
class:
typedef struct String_Struct* String;
struct String_Struct
{
char* (*get)(const void* self);
void (*set)(const void* self, char* value);
int (*length)(const void* self);
};
char* getString(const void* self);
void setString(const void* self, char* value);
int lengthString(const void* self);
String newString();
As can be seen, the methods of the String
class are actually function pointers to the declared function. In preparing the instance of the String
, the newString
function is called in order to set up the function pointers to their respective functions:
String newString()
{
String self = (String)malloc(sizeof(struct String_Struct));
self->get = &getString;
self->set = &setString;
self->length = &lengthString;
self->set(self, "");
return self;
}
For example, the getString
function that is called by invoking the get
method is defined as the following:
char* getString(const void* self_obj)
{
return ((String)self_obj)->internal->value;
}
One thing that can be noticed is that there is no concept of an instance of an object and having methods that are actually a part of an object, so a "self object" must be passed in on each invocation. (And the internal
is just a hidden struct
which was omitted from the code listing earlier -- it is a way of performing information hiding, but that is not relevant to function pointers.)
So, rather than being able to do s1->set("hello");
, one must pass in the object to perform the action on s1->set(s1, "hello")
.
With that minor explanation having to pass in a reference to yourself out of the way, we'll move to the next part, which is inheritance in C.
Let's say we want to make a subclass of String
, say an ImmutableString
. In order to make the string immutable, the set
method will not be accessible, while maintaining access to get
and length
, and force the "constructor" to accept a char*
:
typedef struct ImmutableString_Struct* ImmutableString;
struct ImmutableString_Struct
{
String base;
char* (*get)(const void* self);
int (*length)(const void* self);
};
ImmutableString newImmutableString(const char* value);
Basically, for all subclasses, the available methods are once again function pointers. This time, the declaration for the set
method is not present, therefore, it cannot be called in a ImmutableString
.
As for the implementation of the ImmutableString
, the only relevant code is the "constructor" function, the newImmutableString
:
ImmutableString newImmutableString(const char* value)
{
ImmutableString self = (ImmutableString)malloc(sizeof(struct ImmutableString_Struct));
self->base = newString();
self->get = self->base->get;
self->length = self->base->length;
self->base->set(self->base, (char*)value);
return self;
}
In instantiating the ImmutableString
, the function pointers to the get
and length
methods actually refer to the String.get
and String.length
method, by going through the base
variable which is an internally stored String
object.
The use of a function pointer can achieve inheritance of a method from a superclass.
We can further continue to polymorphism in C.
If for example we wanted to change the behavior of the length
method to return 0
all the time in the ImmutableString
class for some reason, all that would have to be done is to:
length
method.length
method.Adding an overriding length
method in ImmutableString
may be performed by adding an lengthOverrideMethod
:
int lengthOverrideMethod(const void* self)
{
return 0;
}
Then, the function pointer for the length
method in the constructor is hooked up to the lengthOverrideMethod
:
ImmutableString newImmutableString(const char* value)
{
ImmutableString self = (ImmutableString)malloc(sizeof(struct ImmutableString_Struct));
self->base = newString();
self->get = self->base->get;
self->length = &lengthOverrideMethod;
self->base->set(self->base, (char*)value);
return self;
}
Now, rather than having an identical behavior for the length
method in ImmutableString
class as the String
class, now the length
method will refer to the behavior defined in the lengthOverrideMethod
function.
I must add a disclaimer that I am still learning how to write with an object-oriented programming style in C, so there probably are points that I didn't explain well, or may just be off mark in terms of how best to implement OOP in C. But my purpose was to try to illustrate one of many uses of function pointers.
For more information on how to perform object-oriented programming in C, please refer to the following questions:
Function pointers become easy to declare once you have the basic declarators:
ID
: ID is a*D
: D pointer toD(<parameters>)
: D function taking <
parameters>
returningWhile D is another declarator built using those same rules. In the end, somewhere, it ends with ID
(see below for an example), which is the name of the declared entity. Let's try to build a function taking a pointer to a function taking nothing and returning int, and returning a pointer to a function taking a char and returning int. With type-defs it's like this
typedef int ReturnFunction(char);
typedef int ParameterFunction(void);
ReturnFunction *f(ParameterFunction *p);
As you see, it's pretty easy to build it up using typedefs. Without typedefs, it's not hard either with the above declarator rules, applied consistently. As you see i missed out the part the pointer points to, and the thing the function returns. That's what appears at the very left of the declaration, and is not of interest: It's added at the end if one built up the declarator already. Let's do that. Building it up consistently, first wordy - showing the structure using [
and ]
:
function taking
[pointer to [function taking [void] returning [int]]]
returning
[pointer to [function taking [char] returning [int]]]
As you see, one can describe a type completely by appending declarators one after each other. Construction can be done in two ways. One is bottom-up, starting with the very right thing (leaves) and working the way through up to the identifier. The other way is top-down, starting at the identifier, working the way down to the leaves. I'll show both ways.
Construction starts with the thing at the right: The thing returned, which is the function taking char. To keep the declarators distinct, i'm going to number them:
D1(char);
Inserted the char parameter directly, since it's trivial. Adding a pointer to declarator by replacing D1
by *D2
. Note that we have to wrap parentheses around *D2
. That can be known by looking up the precedence of the *-operator
and the function-call operator ()
. Without our parentheses, the compiler would read it as *(D2(char p))
. But that would not be a plain replace of D1 by *D2
anymore, of course. Parentheses are always allowed around declarators. So you don't make anything wrong if you add too much of them, actually.
(*D2)(char);
Return type is complete! Now, let's replace D2
by the function declarator function taking <parameters>
returning, which is D3(<parameters>)
which we are at now.
(*D3(<parameters>))(char)
Note that no parentheses are needed, since we want D3
to be a function-declarator and not a pointer declarator this time. Great, only thing left is the parameters for it. The parameter is done exactly the same as we've done the return type, just with char
replaced by void
. So i'll copy it:
(*D3( (*ID1)(void)))(char)
I've replaced D2
by ID1
, since we are finished with that parameter (it's already a pointer to a function - no need for another declarator). ID1
will be the name of the parameter. Now, i told above at the end one adds the type which all those declarator modify - the one appearing at the very left of every declaration. For functions, that becomes the return type. For pointers the pointed to type etc... It's interesting when written down the type, it will appear in the opposite order, at the very right :) Anyway, substituting it yields the complete declaration. Both times int
of course.
int (*ID0(int (*ID1)(void)))(char)
I've called the identifier of the function ID0
in that example.
This starts at the identifier at the very left in the description of the type, wrapping that declarator as we walk our way through the right. Start with function taking <
parameters>
returning
ID0(<parameters>)
The next thing in the description (after "returning") was pointer to. Let's incorporate it:
*ID0(<parameters>)
Then the next thing was functon taking <
parameters>
returning. The parameter is a simple char, so we put it in right away again, since it's really trivial.
(*ID0(<parameters>))(char)
Note the parentheses we added, since we again want that the *
binds first, and then the (char)
. Otherwise it would read function taking <
parameters>
returning function .... Noes, functions returning functions aren't even allowed.
Now we just need to put <
parameters>
. I will show a short version of the deriveration, since i think you already by now have the idea how to do it.
pointer to: *ID1
... function taking void returning: (*ID1)(void)
Just put int
before the declarators like we did with bottom-up, and we are finished
int (*ID0(int (*ID1)(void)))(char)
Is bottom-up or top-down better? I'm used to bottom-up, but some people may be more comfortable with top-down. It's a matter of taste i think. Incidentally, if you apply all the operators in that declaration, you will end up getting an int:
int v = (*ID0(some_function_pointer))(some_char);
That is a nice property of declarations in C: The declaration asserts that if those operators are used in an expression using the identifier, then it yields the type on the very left. It's like that for arrays too.
Hope you liked this little tutorial! Now we can link to this when people wonder about the strange declaration syntax of functions. I tried to put as little C internals as possible. Feel free to edit/fix things in it.
The guide to getting fired: How to abuse function pointers in GCC on x86 machines by compiling your code by hand:
These string literals are bytes of 32-bit x86 machine code. 0xC3
is an x86 ret
instruction.
You wouldn't normally write these by hand, you'd write in assembly language and then use an assembler like nasm
to assemble it into a flat binary which you hexdump into a C string literal.
Returns the current value on the EAX register
int eax = ((int(*)())("\xc3 <- This returns the value of the EAX register"))();
Write a swap function
int a = 10, b = 20;
((void(*)(int*,int*))"\x8b\x44\x24\x04\x8b\x5c\x24\x08\x8b\x00\x8b\x1b\x31\xc3\x31\xd8\x31\xc3\x8b\x4c\x24\x04\x89\x01\x8b\x4c\x24\x08\x89\x19\xc3 <- This swaps the values of a and b")(&a,&b);
Write a for-loop counter to 1000, calling some function each time
((int(*)())"\x66\x31\xc0\x8b\x5c\x24\x04\x66\x40\x50\xff\xd3\x58\x66\x3d\xe8\x03\x75\xf4\xc3")(&function); // calls function with 1->1000
You can even write a recursive function that counts to 100
const char* lol = "\x8b\x5c\x24\x4\x3d\xe8\x3\x0\x0\x7e\x2\x31\xc0\x83\xf8\x64\x7d\x6\x40\x53\xff\xd3\x5b\xc3\xc3 <- Recursively calls the function at address lol.";
i = ((int(*)())(lol))(lol);
Note that compilers place string literals in the .rodata
section (or .rdata
on Windows), which is linked as part of the text segment (along with code for functions).
The text segment has Read+Exec permission, so casting string literals to function pointers works without needing mprotect()
or VirtualProtect()
system calls like you'd need for dynamically allocated memory. (Or gcc -z execstack
links the program with stack + data segment + heap executable, as a quick hack.)
To disassemble these, you can compile this to put a label on the bytes, and use a disassembler.
// at global scope
const char swap[] = "\x8b\x44\x24\x04\x8b\x5c\x24\x08\x8b\x00\x8b\x1b\x31\xc3\x31\xd8\x31\xc3\x8b\x4c\x24\x04\x89\x01\x8b\x4c\x24\x08\x89\x19\xc3 <- This swaps the values of a and b";
Compiling with gcc -c -m32 foo.c
and disassembling with objdump -D -rwC -Mintel
, we can get the assembly, and find out that this code violates the ABI by clobbering EBX (a call-preserved register) and is generally inefficient.
00000000 <swap>:
0: 8b 44 24 04 mov eax,DWORD PTR [esp+0x4] # load int *a arg from the stack
4: 8b 5c 24 08 mov ebx,DWORD PTR [esp+0x8] # ebx = b
8: 8b 00 mov eax,DWORD PTR [eax] # dereference: eax = *a
a: 8b 1b mov ebx,DWORD PTR [ebx]
c: 31 c3 xor ebx,eax # pointless xor-swap
e: 31 d8 xor eax,ebx # instead of just storing with opposite registers
10: 31 c3 xor ebx,eax
12: 8b 4c 24 04 mov ecx,DWORD PTR [esp+0x4] # reload a from the stack
16: 89 01 mov DWORD PTR [ecx],eax # store to *a
18: 8b 4c 24 08 mov ecx,DWORD PTR [esp+0x8]
1c: 89 19 mov DWORD PTR [ecx],ebx
1e: c3 ret
not shown: the later bytes are ASCII text documentation
they're not executed by the CPU because the ret instruction sends execution back to the caller
This machine code will (probably) work in 32-bit code on Windows, Linux, OS X, and so on: the default calling conventions on all those OSes pass args on the stack instead of more efficiently in registers. But EBX is call-preserved in all the normal calling conventions, so using it as a scratch register without saving/restoring it can easily make the caller crash.
They're very handy to use for when you want different functions at different times, or different phases of development. For instance, I'm developing an application on a host computer that has a console, but the final release of the software will be put on an Avnet ZedBoard (which has ports for displays and consoles, but they are not needed/wanted for the final release). So during development, I will use printf
to view status and error messages, but when I'm done, I don't want anything printed. Here's what I've done:
// First, undefine all macros associated with version.h
#undef DEBUG_VERSION
#undef RELEASE_VERSION
#undef INVALID_VERSION
// Define which version we want to use
#define DEBUG_VERSION // The current version
// #define RELEASE_VERSION // To be uncommented when finished debugging
#ifndef __VERSION_H_ /* prevent circular inclusions */
#define __VERSION_H_ /* by using protection macros */
void board_init();
void noprintf(const char *c, ...); // mimic the printf prototype
#endif
// Mimics the printf function prototype. This is what I'll actually
// use to print stuff to the screen
void (* zprintf)(const char*, ...);
// If debug version, use printf
#ifdef DEBUG_VERSION
#include <stdio.h>
#endif
// If both debug and release version, error
#ifdef DEBUG_VERSION
#ifdef RELEASE_VERSION
#define INVALID_VERSION
#endif
#endif
// If neither debug or release version, error
#ifndef DEBUG_VERSION
#ifndef RELEASE_VERSION
#define INVALID_VERSION
#endif
#endif
#ifdef INVALID_VERSION
// Won't allow compilation without a valid version define
#error "Invalid version definition"
#endif
In version.c
I will define the 2 function prototypes present in version.h
#include "version.h"
/*****************************************************************************/
/**
* @name board_init
*
* Sets up the application based on the version type defined in version.h.
* Includes allowing or prohibiting printing to STDOUT.
*
* MUST BE CALLED FIRST THING IN MAIN
*
* @return None
*
*****************************************************************************/
void board_init()
{
// Assign the print function to the correct function pointer
#ifdef DEBUG_VERSION
zprintf = &printf;
#else
// Defined below this function
zprintf = &noprintf;
#endif
}
/*****************************************************************************/
/**
* @name noprintf
*
* simply returns with no actions performed
*
* @return None
*
*****************************************************************************/
void noprintf(const char* c, ...)
{
return;
}
Notice how the function pointer is prototyped in version.h
as
void (* zprintf)(const char *, ...);
When it is referenced in the application, it will start executing wherever it is pointing, which has yet to be defined.
In version.c
, notice in the board_init()
function where zprintf
is assigned a unique function (whose function signature matches) depending on the version that is defined in version.h
zprintf = &printf;
zprintf calls printf for debugging purposes
or
zprintf = &noprint;
zprintf just returns and will not run unnecessary code
Running the code will look like this:
#include "version.h"
#include <stdlib.h>
int main()
{
// Must run board_init(), which assigns the function
// pointer to an actual function
board_init();
void *ptr = malloc(100); // Allocate 100 bytes of memory
// malloc returns NULL if unable to allocate the memory.
if (ptr == NULL)
{
zprintf("Unable to allocate memory\n");
return 1;
}
// Other things to do...
return 0;
}
The above code will use printf
if in debug mode, or do nothing if in release mode. This is much easier than going through the entire project and commenting out or deleting code. All that I need to do is change the version in version.h
and the code will do the rest!
Starting from scratch function has Some Memory Address From Where They start executing. In Assembly Language They Are called as (call "function's memory address").Now come back to C If function has a memory address then they can be manipulated by Pointers in C.So By the rules of C
1.First you need to declare a pointer to function 2.Pass the Address of the Desired function
****Note->the functions should be of same type****
This Simple Programme will Illustrate Every Thing.
#include<stdio.h>
void (*print)() ;//Declare a Function Pointers
void sayhello();//Declare The Function Whose Address is to be passed
//The Functions should Be of Same Type
int main()
{
print=sayhello;//Addressof sayhello is assigned to print
print();//print Does A call To The Function
return 0;
}
void sayhello()
{
printf("\n Hello World");
}
After That lets See How machine Understands Them.Glimpse of machine instruction of the above programme in 32 bit architecture.
The red mark area is showing how the address is being exchanged and storing in eax.Then their is a call instruction on eax. eax contains the desired address of the function
Function pointer is usually defined by typedef, and used as param & return value,
Above answers already explained a lot, I just give a full example:
#include <stdio.h>
#define NUM_A 1
#define NUM_B 2
// define a function pointer type
typedef int (*two_num_operation)(int, int);
// an actual standalone function
static int sum(int a, int b) {
return a + b;
}
// use function pointer as param,
static int sum_via_pointer(int a, int b, two_num_operation funp) {
return (*funp)(a, b);
}
// use function pointer as return value,
static two_num_operation get_sum_fun() {
return ∑
}
// test - use function pointer as variable,
void test_pointer_as_variable() {
// create a pointer to function,
two_num_operation sum_p = ∑
// call function via pointer
printf("pointer as variable:\t %d + %d = %d\n", NUM_A, NUM_B, (*sum_p)(NUM_A, NUM_B));
}
// test - use function pointer as param,
void test_pointer_as_param() {
printf("pointer as param:\t %d + %d = %d\n", NUM_A, NUM_B, sum_via_pointer(NUM_A, NUM_B, &sum));
}
// test - use function pointer as return value,
void test_pointer_as_return_value() {
printf("pointer as return value:\t %d + %d = %d\n", NUM_A, NUM_B, (*get_sum_fun())(NUM_A, NUM_B));
}
int main() {
test_pointer_as_variable();
test_pointer_as_param();
test_pointer_as_return_value();
return 0;
}
One of the big uses for function pointers in C is to call a function selected at run-time. For example, the C run-time library has two routines, qsort and bsearch, which take a pointer to a function that is called to compare two items being sorted; this allows you to sort or search, respectively, anything, based on any criteria you wish to use.
A very basic example, if there is one function called print(int x, int y) which in turn may require to call add() function or sub() which are of similar types then what we will do, we will add one function pointer argument to the print() function as shown below:-
int add()
{
return (100+10);
}
int sub()
{
return (100-10);
}
void print(int x, int y, int (*func)())
{
printf("value is : %d", (x+y+(*func)()));
}
int main()
{
int x=100, y=200;
print(x,y,add);
print(x,y,sub);
return 0;
}