A pointer to a function points to the address of the executable code of the function. You can use pointers to call functions and to pass functions as arguments to other functions. You cannot perform pointer arithmetic on pointers to functions.
Function pointers can be useful when you want to create callback mechanism, and need to pass address of a function to another function. They can also be useful when you want to store an array of functions, to call dynamically for example.
Function pointers in C can be used to create function calls to which they point. This allows programmers to pass them to functions as arguments. Such functions passed as an argument to other functions are also called callback functions.
The call by pointer method of passing arguments to a function copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the passed argument.
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;
}
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:
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.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With