In this article we will conclude our exploration of C functions with some additional information and some useful techniques for implementing.
In this article we will conclude our exploration of C functions with some additional information and a few useful techniques for implementation.
A basic C function — for example, one or two arguments and a return value — is not a complicated matter. C functions are quite flexible though, and you can write code more easily and introduce some beneficial features into your firmwasre by going beyond the basics.
1. Put your prototype function in a Header file
Sometimes I wonder if a person needs to be a major in computing science to fully understand prototypes of C-language functions. It’s really a rather complicated question. I believe that firmware engineers can safely ignore the details and simply take a standard course of action, such as: always include a prototype for your functions, and place them
A prototype function is one line of code that gives the compiler the data types for the arguments and return value of a function. Take , for example:
Float ArithmeticMean(char Value1, Value2, Value3 char);
It is not actually necessary to include the name of the input parameter, because at this point all the compiler wants to know is the type of data. So you could write the prototype as well as the following:
ArithmeticMean float(char, char, char …);
I prefer to include the names of the parameters, probably because it allows me to create a prototype function by copying and pasting it from a function definition.
Strange things can happen when prototypes are omitted or misplaced, and in my experience the easiest way to eliminate these concerns is to place all of your prototypes in a header file that is included in your entire project
For example, the following code snippet is taken from a file called “Project_DefsVarsFuncs.h”.
void Delay_us(unsigned int DelayCount);
void Delay_10ms(unsigned int DelayCount);
void Delay_seconds(unsigned int DelayCount);
void Update_LCD(unsigned char SensorNumber, unsigned long DisplayValue);
This header file is included in my source files as follows:
2. Declare Functions as Static to avoid conflict-naming
As a firmware project gets bigger and more complicated, you may find you want to reuse the same name in different source files. You can accomplish that by using the keyword “static.” This is a situation where, as described above, you would not be placing the prototype function in a header file.
I ‘d put the “static” keyword in front of the prototype function, and then the prototype function goes to the top of the source file (i.e., before the “normal” code consisting of processor instructions inside function bodies).
Also the “static” keyword like arduino is handy when several engineers are working on the same firmware project. Where two engineers work in different source files.
3. Use a Pointer to pass a function to an Array
Embedded applications frequently make use of arrays — sensor reading sequences, ADC values, short ASCII messages, etc. It might seem that functions are a bit awkward in this sort of development context, because you cannot pass an array to a C function. Well, it’s true you can’t pass an array in the way you go through an individual vari
If you include a pointer as one of the arguments and then pass the array identifier when calling the function, the function body statements can use that pointer to read and modify the array contents. If you find this concept somewhat confusing, I recommend that you first read my C array article, and then the first pointer article.
4. You can use a pointer to call functions
A pointer is a variable that has an address to the memory. This address often identifies where a variable or the zero element of an array is located. Pointers can however point to functions as well.
If you read my first article about C functions, you know that functions are stored in code memory at specific locations just as variables are stored in data memory at specific locations. If a function’s starting address is the value stored in a pointer, that function can be called using the pointer. If you change the pointer’s value such that it equals the starting address of a different function
5. When possible, use local variables
I think our first instinct in many cases is to define all the variables at the top of the source file and leave them at that. It’s good however to get used to using local variables in your functions. The scope of a local variable is limited to the function it is defined in; in other words, when the function is called and di is created
For two reasons, I recommend Local variables. First, they allow you to reuse the same name variable in various functions. A complicated project can include numerous functions requiring basic variables like a loop counter. I like using “n” for my loop counters repeatedly, instead of cycling through all the letters in the alphabet.
Here we covered quite a few details regarding the use of functions in the C language, and I hope this information will help you make your firmware more efficient and functional (no pun intended). If you have any tips related to the function, please feel free to share them in the comments section below.