{"id":4172,"date":"2022-05-23T08:30:00","date_gmt":"2022-05-23T06:30:00","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4172"},"modified":"2025-12-27T15:46:02","modified_gmt":"2025-12-27T14:46:02","slug":"how-to-properly-construct-a-function-pointer-callback","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/how-to-properly-construct-a-function-pointer-callback\/","title":{"rendered":"How to Properly Construct a Function Pointer (Callback)?"},"content":{"rendered":"\n<p>I\u2019m coming today with an interesting topic. It will be a pointer to a function. Unlike \u201cregular\u201d pointers, they are a bit harder. Because&nbsp;<strong>functions define more things than just a regular variable.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pointer to a function<\/h2>\n\n\n\n<p>Pointers can point to&nbsp;<strong>any memory cell<\/strong>, and our program code is nothing more than successive instructions in Flash memory. So you can point to it.<\/p>\n\n\n\n<p>The compiler in cooperation with the linker handles determining a function\u2019s address very well.<\/p>\n\n\n\n<p>A function has certain fixed elements. These are&nbsp;<strong>arguments and the returned result.<\/strong>&nbsp;We provide these things from the outside, but inside the function is always the same. After all, it resides in non-volatile memory \u2013 Flash.<\/p>\n\n\n\n<p>In reality, the function code always uses the arguments in the same way, in the same order, and always returns the result the same way. Only the data \u201cunderneath\u201d changes. The operations are always the same \ud83d\ude42<\/p>\n\n\n\n<p>So if we provide in code the address of a function together with the list of arguments it requires, then in fact we can point to any function. Having two functions with the same arguments means that we can call them \u201cinterchangeably\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Function pointer structure<\/h2>\n\n\n\n<p>How to build a function pointer? I already mentioned to you that&nbsp;<strong>the compiler must know the entire required list of arguments and the \u201creturn value\u201d.<\/strong>&nbsp;This will have to be attached to the pointer.<\/p>\n\n\n\n<p>Another important element is informing the compiler that this is a pointer<strong>&nbsp;to a function.<\/strong>&nbsp;How? By adding the&nbsp;<strong>function call operator,<\/strong>&nbsp;that is, parentheses on the right side of the identifier.<\/p>\n\n\n\n<p>Let\u2019s take an example, the simplest function:<\/p>\n\n\n\n<p><strong>void MyFunction(void) { \u2026 }<\/strong><\/p>\n\n\n\n<p>Never mind what it does.<\/p>\n\n\n\n<p>How to build a pointer to it? First,&nbsp;<strong>the name&nbsp;<\/strong>of the pointer and indicating that it will be a&nbsp;<strong>pointer<\/strong>.<\/p>\n\n\n\n<p><strong>(*FunPtr)<\/strong><\/p>\n\n\n\n<p>Let\u2019s put it in parentheses right away so that operator binding order doesn\u2019t win out. We have a pointer named FunPtr. We still don\u2019t know what type or what it points to.<\/p>\n\n\n\n<p>It is to be a pointer to a function, so we must add the function call operator. In the same way we wrote the function.<\/p>\n\n\n\n<p><strong>(*FunPtr)()<\/strong><\/p>\n\n\n\n<p>This is already a function pointer. Now&nbsp;<strong>the entire litany of arguments and the return type.<\/strong>&nbsp;The compiler&nbsp;<strong>MUST&nbsp;<\/strong>know this. It must know what&nbsp;<strong>EXACTLY&nbsp;<\/strong>the pointer points to. After all, we need to pass those arguments from the outside somehow.<\/p>\n\n\n\n<p>Our function took nothing and returned nothing, so it\u2019s simple.<\/p>\n\n\n\n<p><strong>void (*FunPtr)(void)<\/strong><\/p>\n\n\n\n<p>In the arguments, you provide only their types. In the order that the function accepts them. Now we can assign the function to the pointer.<\/p>\n\n\n\n<p>The function name itself is converted to its address. That\u2019s what is used here. The pointer name is also an address. So we use just the names. The correctness of the remaining elements is checked by the compiler \u201cin the background\u201d.<\/p>\n\n\n\n<p><strong>FunPtr = MyFunction;<\/strong><\/p>\n\n\n\n<p>From now on the FunPtr pointer points to our function.&nbsp;<strong>How to call the function via the pointer?&nbsp;<\/strong>With the function call operator \ud83d\ude42<\/p>\n\n\n\n<p><strong>FunPtr();<\/strong><\/p>\n\n\n\n<p>If FunPtr is an address in memory, then the parentheses tell the compiler \u201ccall the function at this address\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A more difficult pointer<\/h2>\n\n\n\n<p>Ok, that was trivial because we had no arguments. Let\u2019s do something crazy. Let\u2019s point to an example transfer function:<\/p>\n\n\n\n<p><strong>uint8_t ReadFromI2C(uint8_t Address, uint8_t Register, uint8_t *Data, uint16_t Size){\u2026}<\/strong><\/p>\n\n\n\n<p>The function accepts in its arguments:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>I2C device address<\/li>\n\n\n\n<li>register address in the device<\/li>\n\n\n\n<li>pointer to the array for receiving data<\/li>\n\n\n\n<li>amount of data read (e.g., with auto-increment)<\/li>\n<\/ul>\n\n\n\n<p>An error code is returned as uint8_t. If no error, then zero. If error, then something else.<\/p>\n\n\n\n<p><strong>How to build a pointer that points to such a function? Let\u2019s go!<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We need an identifier<\/li>\n<\/ol>\n\n\n\n<p><strong>ReadFromI2CPtr<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Now let\u2019s say that this is a pointer<\/li>\n<\/ol>\n\n\n\n<p><strong>(*<\/strong>ReadFromI2CPtr<strong>)<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>What the pointed-to function returns<\/li>\n<\/ol>\n\n\n\n<p><strong>uint8_t&nbsp;<\/strong>(*ReadFromI2CPtr)<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The entire list of arguments in the same order as the function we want to point to (types only)<\/li>\n<\/ol>\n\n\n\n<p>uint8_t (*ReadFromI2CPtr)<strong>(uint8_t, uint8_t, uint8_t*, uint16_t);<\/strong><\/p>\n\n\n\n<p>And done! Was it hard? I hope not \ud83d\ude42<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Passing a function pointer to a function as an argument<\/h2>\n\n\n\n<p>Often we will want to pass such a function pointer as an argument. In the next email we\u2019ll deal with callbacks, and that\u2019s exactly where function pointers are used.<\/p>\n\n\n\n<p>How do we pass such a pointer? With a pointer to a variable, we provided the pointer type. How here?<\/p>\n\n\n\n<p><strong>This whole litany is the type of the pointer.<\/strong><\/p>\n\n\n\n<p>If we want to pass a function pointer as an argument, we must&nbsp;<strong>EXACTLY&nbsp;<\/strong>describe what kind of function it is.<\/p>\n\n\n\n<p>As a reminder, a function is described by:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>name (address in Flash)<\/li>\n\n\n\n<li>types, order, and number of arguments<\/li>\n\n\n\n<li>return type<\/li>\n<\/ul>\n\n\n\n<p>For example, let\u2019s take this more difficult function, or rather its prototype.<\/p>\n\n\n\n<p><strong>uint8_t ReadFromI2C(uint8_t Address, uint8_t Register, uint8_t *Data, uint16_t Size) { \u2026 }<\/strong><\/p>\n\n\n\n<p>We want to pass the address of this function as an argument. What will the prototype of the function that takes the address of such a function look like?<\/p>\n\n\n\n<p>void MyFun2(&nbsp;<strong>??&nbsp;<\/strong>) { \u2026 }<\/p>\n\n\n\n<p>Think for a moment\u2026 You have to pass all information about the function being pointed to.<\/p>\n\n\n\n<p>Done?<\/p>\n\n\n\n<p>Do you know? \ud83d\ude42<\/p>\n\n\n\n<p>Since a function pointer must be precisely specified, it will look the same as if we were creating a standalone pointer.<\/p>\n\n\n\n<p>void MyFun2(<strong>&nbsp;uint8_t (*FunctionPtr)(uint8_t, uint8_t, uint8_t*, uint16_t)&nbsp;<\/strong>){ \u2026 }<\/p>\n\n\n\n<p><strong>This is ONE argument<\/strong>! A pointer to a function that returns uint8_t and takes 4 arguments according to the given types. Yes, I know\u2026 it looks terrifying.<\/p>\n\n\n\n<p>Fortunately, using this function itself and passing to it the address of a function is simpler.&nbsp;<strong>What is the address of a function?<\/strong><\/p>\n\n\n\n<p><strong>Its name!&nbsp;<\/strong>So the concrete call of this function with the nightmarish pointer argument will look simpler:<\/p>\n\n\n\n<p>MyFun2(&nbsp;<strong>ReadFromI2C&nbsp;<\/strong>);<\/p>\n\n\n\n<p>That\u2019s it. The function name&nbsp;<strong>ReadFromI2C&nbsp;<\/strong>is its address.<\/p>\n\n\n\n<p>Now the compiler<strong>&nbsp;looks and analyzes<\/strong>:<\/p>\n\n\n\n<p>\u201cOookay\u2026 function&nbsp;<strong>MyFun2&nbsp;<\/strong>(based on the prototype) takes the address of a function that returns uint8_t and takes arguments of type uint8_t, uint8_t, pointer to uint8_t and uint16_t.&nbsp;<\/p>\n\n\n\n<p>You passed me, dude,&nbsp;<strong>the address of some function ReadFromI2C<\/strong>, so let\u2019s take a look at what it looks like (based on the prototype).<\/p>\n\n\n\n<p><strong>ReadFromI2C&nbsp;<\/strong>(based on the prototype) returns uint8_t and takes arguments of type uint8_t, uint8_t, pointer to uint8_t and uint16_t.<\/p>\n\n\n\n<p>Everything matches! We can compile!\u201d<\/p>\n\n\n\n<p><strong>If there is any mismatch, the compiler will tell you right away!<\/strong><\/p>\n\n\n\n<p>The key is to understand that&nbsp;<strong>a function pointer MUST be described very precisely.<\/strong>&nbsp;It must fully define the function prototype. I\u2019ll remind you once again, because this is important:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>name (address in Flash)<\/strong><\/li>\n\n\n\n<li><strong>types, order, and number of arguments<\/strong><\/li>\n\n\n\n<li><strong>return type<\/strong><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Most common mistakes<\/h2>\n\n\n\n<p>I see a few mistakes in attempts to use function pointers. The most important ones:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Missing the function call operator<\/strong><\/li>\n<\/ol>\n\n\n\n<p>If the pointer points to a function, then in its declaration it must include the function call operator.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Missing parentheses that \u201cseparate\u201d the function call from the pointer<\/strong><\/li>\n<\/ol>\n\n\n\n<p>Parentheses, i.e., the function call operator, have&nbsp;<strong>HIGHER&nbsp;<\/strong>precedence than the pointer operator, i.e., the asterisk *<\/p>\n\n\n\n<p>So when writing<\/p>\n\n\n\n<p>uint8_t *ReadFromI2CPtr(uint8_t, uint8_t, uint8_t*, uint16_t);<\/p>\n\n\n\n<p>We actually have<strong>&nbsp;a function prototype that returns a pointer, not a pointer declaration!<\/strong><\/p>\n\n\n\n<p><strong>There must be parentheses that include the asterisk and the identifier (name) of the pointer.<\/strong><\/p>\n\n\n\n<p>uint8_t&nbsp;<strong>(<\/strong>*ReadFromI2CPtr<strong>)<\/strong>(uint8_t, uint8_t, uint8_t*, uint16_t);<\/p>\n\n\n\n<p>Now the pointer has precedence, and only then the function call operator. Now it is a function pointer.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Argument mismatch<\/strong><\/li>\n<\/ol>\n\n\n\n<p>We don\u2019t have freedom with function pointers. More precisely, we do not create a \u201cfunction pointer\u201d as something general.<\/p>\n\n\n\n<p>We create a&nbsp;<strong>very specific \u201cpointer to a function that takes X1, X2, X3\u2026Xn and returns Y.\u201d<\/strong>&nbsp;Therefore, a mismatch of even one element X or Y will break compilation.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Using parentheses when passing the address of a function<\/strong><\/li>\n<\/ol>\n\n\n\n<p>Parentheses are the function call operator. If we want to extract just the address of a function, we use&nbsp;<strong>ONLY THE NAME<\/strong>&nbsp;of the function. Without parentheses. Parentheses will cause that instead of passing the address\u2026 we will call the function.<\/p>\n\n\n\n<p>The situation is similar to pointers to data:&nbsp;<strong>The name itself = address.&nbsp;<\/strong>The name with an asterisk is the value at that address.<\/p>\n\n\n\n<p>For a function, the&nbsp;<strong>name itself = address<\/strong>. The name with parentheses is calling the function at that address.<\/p>\n\n\n\n<p>Maybe I\u2019m repeating myself, but this is key to understanding pointers \ud83d\ude42 What is \u201cjust\u201d an address, and what is \u201csomething useful\u201d hidden under that address.,<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>As you can see, it\u2019s a bit harder than a regular pointer to data. No mercy. In C, a lot of things rest on the programmer. Many things must be determined in advance. Among other reasons, that\u2019s why C is efficient \ud83d\ude42<\/p>\n\n\n\n<p>Study this email carefully once again. Test in the&nbsp;<a href=\"https:\/\/www.onlinegdb.com\/online_c_compiler\" target=\"_blank\" rel=\"noreferrer noopener\">online compiler<\/a>&nbsp;assigning a function address to a pointer. Call the function using the pointer. Create some complicated function and try changing things so that errors show up.<\/p>\n\n\n\n<p>You have to practice and experiment.<\/p>\n\n\n\n<p>Why do I press so hard on this function pointer?<\/p>\n\n\n\n<p><strong>We\u2019ll need it for so-called Callbacks.<\/strong>&nbsp;<strong>In common use, they utilize function pointers.<\/strong><\/p>\n\n\n\n<p>This will be an important topic, because callbacks are used quite intensively in microcontroller programming.<\/p>\n\n\n\n<p><strong>Be sure to let me know in the comments whether this article was understandable for you! If you don\u2019t understand something, write! It\u2019s important.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Do you want to learn the C language with microcontrollers in mind?<\/h2>\n\n\n\n<p>I created a course dedicated to microcontrollers. <strong>I teach C in it from scratch. Everything I discussed in this post (and much, much more) is included in the course syllabus.<\/strong> (The course is conducted in Polish.)<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/cdlamikrokontrolerow.pl\/webinar\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"99\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/10\/Kurs-C-dla-embedded-logo-500px.jpg\" alt=\"\" class=\"wp-image-1967\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/10\/Kurs-C-dla-embedded-logo-500px.jpg 500w, https:\/\/msalamon.pl\/wp-content\/uploads\/2021\/10\/Kurs-C-dla-embedded-logo-500px-300x59.jpg 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><\/figure>\n\n\n\n<p><strong>I gathered my experience from several years of embedded programming<\/strong> and I want to pass on the best possible knowledge to you. I participated in various projects: solo, startup, a mid-sized company, and a huge corporation.<\/p>\n\n\n\n<p>In addition to the basics and syntax, <strong>I share a ton of best practices.<\/strong> I weave this in between explaining subsequent aspects of the C language.<\/p>\n\n\n\n<p>An additional advantage is also that I show <strong>how to run a project well.<\/strong> I\u2019ll show you how to deal with building abstraction layers. We\u2019ll use <strong>structures, pointers, and callbacks.<\/strong> And of course splitting into files. That helps a lot.<\/p>\n\n\n\n<p>Such separated layers are much easier to \u043f\u0435\u0440\u0435\u043d\u043e\u0441 between projects, and even between different microcontroller families.<\/p>\n\n\n\n<p><strong> <strong>Join the waiting list for the course and start learning together with the materials I prepared. After signing up, you will receive weekly emails about the C language (the newsletter is conducted in Polish): <a href=\"https:\/\/cdlamikrokontrolerow.pl\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/cdlamikrokontrolerow.pl<\/a><\/strong> <\/strong><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4172&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;How to Properly Construct a Function Pointer (Callback)?&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>I\u2019m coming today with an interesting topic. It will be a pointer to a function. Unlike \u201cregular\u201d pointers, they are a bit harder. Because&nbsp;functions define more things than just a regular variable. Pointer to a function Pointers can point to&nbsp;any memory cell, and our program code is nothing more than [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3733,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[176,174],"class_list":["post-4172","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-programming","tag-stm32"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4172"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4172\/revisions"}],"predecessor-version":[{"id":4175,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4172\/revisions\/4175"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3733"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}