My Pages

Monday, July 25, 2011

(*function) pointers

Ok, now that we've covered some really cool things like pointers and double pointers; it's time to step things up a notch and look at function pointers. So let's start off with the two main things that come along with learning function pointers; what is a function pointer, and why do I care about a function pointer... So what IS a function pointer? Well let's think back to what exactly a pointer IS. A pointer is a storage of a memory location (remember from the previous post Pointers with *, &, ->, . ).

Now that we're all acclimated back into the world of pointers; or some are more confused now let's proceed! So the thing we need to keep in mind is how applications work. I'm really not going to get into all the theory that goes into program counters and heaps/stacks because it's really boring and actually causes more confusion than is necessary (yes, when working in pointer~land a certain level of confusion is ALWAYS necessary). I'm also not going to get debugging, as such I'm going to lay down some B.S. that looks cool but still makes sense.

So, functions exist as a point in memory as the start of an execution scope; I know what you're thinking, "what in the hell does that mean?" Well it's pretty straight forward, every function is a separate scope; this means that the variables that exist in function A are not available in function B (unless of course we pass them between each other). As such, there is always an entry point of the function, if you are familiar with gdb then you can see this happen with the "call" OP. If you didn't understand what that means don't worry it's not a huge deal for you; just know that there is a single point where the function starts, THIS is the pointer of the function. So let's assume this:

0x01 start function
0x02 do some work
0x03 do some more work
0x04 do even more work
0x05 return


So when we define a function pointer, it will take the memory address (remember points contain memory addresses) of the start of the function. From our example above, it will contain 0x01. So the question is, how does this actually work? Well, technically speaking it doesn't; OK you're a piece of shit, why are you telling me things that don't work!? Hold on, calm down; it's not that it doesn't work, it's that the compiler MAKES it work. See the compiler knows when you are using a function pointer; as such, the compiler knows to perform the function execution. It's not really imperative to know how this works, but more important that you know that the compiler understands that when you call the function pointer it is essentially the same as calling a normal function.

Ok, so tons of talking about what function pointers are, but how are function pointers defined? Well, it's pretty straight forward; the main thing you need to remember is that (*) is the definition of a function pointer; the rest looks like a normal function. Huh? That makes no sense; sure it does! Let's look at a function pointer, the function is defined as:

void function(int i, void *ptr);


So what does the function pointer look like? The name of our variable is 'var'
void (*var)(int, void *);


That's it? Yea, not that bad at all right? So how do I need to accept these types of pointers into another function? I mean, what happens if I wanted to accept a function that I wanted to call causing the execution to be determined at run time? The variable name of the function pointer is actually 'func'.

void my_function(void (*func)(int , void *));


Alright, now we're cooking with gas! So, here's the next question; how do I execute this damned thing!? Well there are two ways, there is the syntactically correct way to do this. Let's assume that we have an integer i, and of course our great friend NULL (although this could be any pointer). We'll assume we are executing the function 'ex' from our first example.

(*ex)(i, NULL);


So I mentioned that this was the syntactically correct way to execute the function pointer; is there a different way? Yes, actually there is! You can execute function pointers just like you would a normal function. WHAT? Why the hell would you teach me this crazy ass syntax!? Because, if I didn't you would see it somewhere and shit a brick trying to understand what in the hell it actually meant. We assume we have i as an integer again and now we're executing 'func'

func(i, NULL);


So much easier to understand! Yes, it is. So now that we understand the syntax; let's cover a few examples of why anyone would want to be able to do a function pointer. Well if you think about arrays, or linked lists (if you don't know about linked lists, just relate back to the array idea and stick with it). So, what happens if you want to perform a sorting routine (yes, I do realize that everyone and their brother has done this but hey; it assists in understanding the concept so calm down and listen up) but you want it to be flexible for every possible sorting style you wanted. What does this mean? Well let's say that I have a list of structs, I have a specific way I want to sort this array. Well, what happens if I want to sort it differently later; do I write a whole new function for sorting in this same method? NO! We use function pointers!

By using function pointers, we can pass a function pointer to the sorting routine that will be called which will be called on each element and will assist in sorting the elements of the array. What does this mean? Let's say we have a function definition:

void sort_my_shit(MyStruct *arr, int len, 
int (*compare)(MyStruct *s1, MyStruct *s2));


That's freakin' AWESOME! But, I hate this syntax; is there anything easier to write? Of course, if you remember in C; there is this thing called typedef's. So let's look at our example that we've been checking out but with a typedef.

typedef void (*MyFunctionPointer)(int , void *);


What the hell, you just repeated that thing from the first example with the 'ex' function pointer! You are correct, but I did add the typedef to the beginning. Really this is it? How would I use this to define a function pointer? It's pretty simple, at this point you just use 'MyFunctionPointer' just like a normal pointer.

MyFunctionPointer our_function;


WHAT? Are you freakin' serious!? You've been making type in all this junk before when I could've just typed in one line and made life so much easier!? Yes, again; just trying to get you used to the syntax; because assholes like me like writing out long hand the function pointer definitions rather than the typedefs because I hate seeing a million different type names residing everywhere. Get used to it... How do you accept the function pointer?

void newFunction(MyFunctionPointer our_function);


OH MY GOD YOU ARE AN ASS!! Yes, I am; I've been showing you tons of difficult syntax but guess what; when you stumble across the long hand syntax you'll be glad that I brought you into it because now it makes a little more sense to you. If you think about the command/strategy/state patterns of OOP, you can actually implement these types of patterns THROUGH function pointers. Maybe I'll cover that in my next post; but for the time being check it out, you can start to make partial classes through utilization of function pointers.

Wait, I can make C more objective? Yes! Isn't that awesome; the only problem is that you have to do some work to get it to be more objective. Check this struct out.

typedef struct MyClass {
void (*func)(struct MyClass *this, int var);
} MyClass;


Now you call the method (assuming that our variable for MyClass is cl and an integer i).

cl->func(cl, i);


AHHHHHHHHHH, HEAD 'SPLODE!!!!!! Calm down; this is one of those things that people freak out about; just think about this; if you actually do a gdb on a C++ application and break during the method of a class you will actually see the method being almost the SAME thing where this is actually a method parameter (that is automatically passed in by the compiler during execution). Pretty interesting right? I thought so; just remember, pointers are NOT that difficult to understand; that are hard to master.

No comments: