Why Function Pointers are Awesome

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to the embedded online conference i'm jacob veningo and in this micro talk we're going to be talking about why function pointers are awesome now you might have heard otherwise you might have actually heard that function pointers are evil and part of the reason why we often have this rumor is can we kind of trace back to miseracy 1998 the rule number 104 now this interesting rule states that non-constant pointers to functions shall not be used and what has happened from this is that people have said oh function pointers are evil we shouldn't be using these and if you look a little bit closer at the actual rule you know it does say yes there is a danger with pointers calculated at runtime that can cause an error with the pointer and have it point to basically an arbitrary location so the concern is that hey if we have this pointer at runtime this thing can get corrupted it could point to who knows what in memory and we could end up with unexpected operations of our embedded systems now because of this people have said nope never use function pointers again they're evil but if you look a little bit closer at this rule you'll actually find that it says non-constant pointers to function shall not be used now it actually turns out that later versions of mr c actually rescinded this rule 104 but i still find a lot of people get confused and you know in my courses or when i'm consulting with people they'll say oh you can't use function pointers that's not allowed and of course it is allowed but it actually turns out that if we get rid of this whole idea of not using function pointers you'll find out that function pointers actually have a lot of really cool awesome use cases so let's take a look at a couple of these use cases first of all function pointers can be used for callback functions now a callback function it basically allows you to assign a different function that will be called based on what the application needs to do now the safe way to do this of course is to statically or at compile time decide what function you're going to use now you could also do it dynamically during runtime and that's kind of what this example shows just because it's very easy to show people um you know how a callback would actually work we basically have an application section here a layer here we have a driver layer or the kernel here this is probably pre-compiled we can't change how what its behavior is we probably want our interrupt service routines or our signal handlers to change behaviors from one application to the next or you know especially if we're using our code across multiple product lines or might have different types of functions or filters that we want to use in different circumstances in those types of cases in a dynamic version you might have the main function actually register a function pointer with uh the lower level kernel that then knows hey when the signal when the signal handler or interrupt service routine runs i can i have the pointer back to the application code and i can run application code from the lower level code without having to make a whole bunch of changes now again the recommendation here to do it safely would be to statically allocate this and if you want to learn a little bit more about this type of use case you can actually visit my blog here at the very bottom we just don't have the time in a micro talk to discuss all the details and how we actually set those types of things up now the second use case for function pointers is for command processing when i first started writing embedded software when i was a you know undergrad or grad student um one of the thing actually i started well before that but uh one of the things that i used to do was i would use these gigantic switch case statements and i was working on flight software one time and we literally create we had we had over over 100 commands probably close to 200 commands that we have to process on this flight computer and we use a switch statement to do that so we had like 200 cases and we had this horrible piece of code that we were trying to maintain it was probably somewhere along the lines of 10 to 20 000 lines of code all in this one switch case statement a horrible thing but at some point i discover that hey you know what it's a far better way to actually use function pointers we could actually based on the command that comes in allocate or direct or map a particular function to a function pointer and invoke a function to handle all the code that was needed all those unwieldy switch case statements completely went away now what ends up happening is that instead of all these switch case statements you end up with some a nice little a table array that looks like this now what ends up happening here is that we have basically a typed up enumeration that's nice and human readable that then is associated that goes in the structure we create a list basically an array of that structure and then the first row or first column in the table here is actually just a nice readable um enumerated type for us the second one the second entry in this uh in the structure actually turns out to be um in the second column as well is actually a list of all the function pointers that we want associated with the command on the left here so what ends up happening is i can build out a very nice list of commands and the pointers that are going to be mapped to them and then when i reference this this array here i can dereference or access one of the elements of the array and i can access the actual function pointer here and de-reference it and run whatever the command wanted so it makes the code a lot cleaner reusable very scalable makes it very easy to add new commands or remove other commands without having to go through a lot of code now you might be wondering here you know is this really safe for use with embedded systems now the key here thing here to look at is i've declared this array that i'm using the structured array of function pointers to be static so that i limit the scope so that i can't link you know i can't allow people elsewhere in the code to link to this and try to modify my table and then secondly i declare it as const now making this a constant array of structures essentially what i'm doing is i'm tr hopefully when i compile this the const is telling the compiler to store this in flash rather than in ram and what will happen is that these will be constant function pointers stored in flash and what will happen is because they're not in ram even if i got bit flips or or crazy things happening in ram um memory corruption these function pointers would be constant they shouldn't change so in most embedded compilers by default anything that's constant will be stored in flash and access from flash unless you go and change any of your compiler settings so if you're using function pointers make sure that they are stored in a location where they really can't be changed you don't want these in in flash otherwise you really are starting to disobey some of the miserable rules and you're opening yourself up to allowing a function pointer which could be called to become corrupted if that memory location gets corrupted by something else in the system now another really cool use case is for schedulers you really can't create a time-based scheduler or real-time operating system without using function pointers they can be extremely useful they're a great tool especially if they're used properly now what ends up happening here is you can end up again with a nice uh a nice little uh table array essentially of function pointers associated with um the things necessary to actually run a task now again if you're using real-time operating system you'll normally want to do this statically although there are usually options to do this dynamically as well when you create tasks and things like that um so if you are interested in learning a little bit more about how you can use function pointer to schedulers uh a while back i think probably almost almost a decade not quite seven or eight years ago i wrote a little blog about how you actually go about doing this so you can dive into those details a little bit more if you're interested now another cool use case another thing that makes function pointers awesome is that we can use them for state machines again you can create a table like structure to be able to create functions that point to the different states that will be executed and then when you actually run your code you can use a simple function like this a function that returns nothing just as the example it's a state machine it's a run function for the state machine and what i do here you can see here because we have we would have our states in some type of array of function pointers again or a structure of um you know that includes a numeric type and a function pointer what ends up happening here is if you were to de-reference that array outside the bounds of what was defined for the function pointers you could be calling either something outside of the memory bounds or you could be calling something that does exist in memory but wasn't designed to be called and then you can just kind of your system can go off into the weeds essentially so one of the one key thing to do there is that if you do use arrays of function pointers when you dereference them you want to make sure you have some code that says hey i'm about to de-reference this thing does it make sense is it within the bounds that i designed for this function pointer table and that's all i'm doing here there might be some variable called state machine state um you know when we run here it's being manipulated to decide what state the system is in and then i'm i just want to make sure that it's within the allocated state so num states for example might be five and as long as uh state machine um state is less than five then what we will go through we'll do reference the table that we create for our states and then we just dereference the function pointer right there so again pretty simple and straightforward um again in our microtalk don't have time to go over every single detail but some of my older blogs talk about this as well that you can follow up with a little bit later as well now this is just a couple of the use cases there's so many more things we can use function pointers for interrupt vector tables we can use them in communication interfaces we can use them to simplify our switch statements which i kind of already mentioned uh we can use it to emulate some type of polymorphism as well within our c code which is pretty cool uh we can do compile time selection of functions during implementation uh we can also do it during runtime although again that starts to get kind of dangerous in case you have bit flips or memory corruption it can affect the way that your function it can affect if you dereference a function pointer what code will actually get executed but there's so much more that can be done here it's really quite cool now again because function pointers are awesome and i'm hoping that you will investigate how to safely use them i do want to warn you at the end here too be careful they can be dangerous it's why there are major rules that specify how you should properly use function pointers you know limit the scope for tables if you create tables of function pointers limit their scope so other code modules can't accidentally link to them and modify them in any way make sure that those function pointers are not stored in ram make sure that you perform runtime checks to make sure that they're not null that they're pointing to realistic locations and that they you know haven't been modified in some way that the address actually makes sense you can even use your preprocessor directives or even use the memory protection unit to ensure that any region that has a function pointer that's being dereferenced that it's limited to that specific range and you can easily check and make sure that that's not going to get corrupted so and of course don't try to do anything that's weird per se or clever because what will happen is some bug will you know bite you and your system will end up with some strange behavior that takes way too long to debug so if you do want to learn a little bit more or learn about more about what i do in the embedded systems industry feel free to hop over to boningo.com you'll be able to find all kinds of additional articles and information and a little bit about myself as well thank you very much for attending this micro talk i hope that you found it useful and that you will also enjoy the embedded online conference we got a lot of great talks lined up and i look forward to answering any of your questions thank you
Info
Channel: Jacob Beningo
Views: 5,013
Rating: undefined out of 5
Keywords:
Id: PcAD6gjNUVw
Channel Id: undefined
Length: 11min 10sec (670 seconds)
Published: Tue Mar 22 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.