When you have really small snippets of code that are repeated several times in your micro controller program, is it better to write a method? I mean better in terms of performance and storage usage. I know that when programming for PC, code repetition is a big no go, but what about micro controllers?
In the following example (Arduino Nano with Adafruit 2,8" cap touch display) the snippet should look if the back button is pressed in several screens. I checked in the Arduino IDE how much storage each version takes:
Version 1, 15114 Bytes for complete program:
void battScreen(TS_Point p){
// some other code
// ....
if ((p.x > backBox.posx) && (p.x < backBox.posx + backBox.sidex)){
if((p.y > backBox.posy) && (p.y < backBox.posy + backBox.sidey)){
screen = MAIN1;
showMainScreen();
}
}
}
void alarmScreen(TS_Point p){
// some other code
//...
if ((p.x > backBox.posx) && (p.x < backBox.posx + backBox.sidex)){
if((p.y > backBox.posy) && (p.y < backBox.posy + backBox.sidey)){
screen = MAIN1;
showMainScreen();
}
}
}
void pumpScreen(TS_Point p){
// some other code
// ...
if ((p.x > backBox.posx) && (p.x < backBox.posx + backBox.sidex)){
if((p.y > backBox.posy) && (p.y < backBox.posy + backBox.sidey)){
screen = MAIN1;
showMainScreen();
}
}
}
Version 2, 15234 Bytes for complete program:
void checkBack(TS_Point p){
if ((p.x > backBox.posx) && (p.x < backBox.posx + backBox.sidex)){
if((p.y > backBox.posy) && (p.y < backBox.posy + backBox.sidey)){
screen = MAIN1;
showMainScreen();
}
}
}
void battScreen(TS_Point p){
// some other code
// ...
checkBack(p);
}
void alarmScreen(TS_Point p){
// some other code
// ...
checkBack(p);
}
void pumpScreen(TS_Point p){
// some other code
// ...
checkBack(p);
}
As you can see, version 2 with the extra method takes 120 Bytes more storage. Is there a rule of thumb when it makes sense to create a new method instead of copying code?
-
Maybe the following question also gives you some insight: stackoverflow.com/questions/144993/…Michel Keijzers– Michel Keijzers2017年11月27日 14:42:38 +00:00Commented Nov 27, 2017 at 14:42
-
Your comparison is quite strange; functions take LESS space than copying code. I'll try implementing it, since I think there is some other issue with your specific codefrarugi87– frarugi872017年11月27日 14:44:11 +00:00Commented Nov 27, 2017 at 14:44
-
2Also (except for the interesting result), not to optomize if it is not needed. Mostly readability, maintainability favors above performance or used flash memory.Michel Keijzers– Michel Keijzers2017年11月27日 14:44:18 +00:00Commented Nov 27, 2017 at 14:44
-
1@frarugi87 This is possible, although I just changed the code as in the question. Maybe (part of) the reason is what Code Gorilla wrote in his answer with copying variables.Lehue– Lehue2017年11月27日 14:48:19 +00:00Commented Nov 27, 2017 at 14:48
2 Answers 2
It.... depends
A call to function involves a few things
- Save the context
- Move the parameter(s) to the appropriate registers
- Enter the function
- Execute
- Eventually save the return value to a register
- Restore the context
- Eventually copy the returned value to the variable
As you can see, quite a lot of things. The bold points are the ones executed also if you don't use a function.
Please note that if these functions are "methods", you have also a "hidden" parameter (the object you are applying the method onto)
So why use functions? Well, you will have to write this code in flash only once instead of more times.
What is best? It depends on your application.
- You are calling this function only once? Don't use a function
- Your function is really short (for instance, a one-liner)*? Don't use a function
- You are running out of flash memory? Use a function
- You need a lot of speed? Don't use a function (you add overhead)
You are not in one of the previous cases? Do as you prefer
- With one-liner I mean something like, for instance,
byte sum(byte a, byte b) { return a + b; }
; in this case the function also occupies more space, since the call function instruction is compatible with the byte sum
- With one-liner I mean something like, for instance,
Please note that usually more readability is more important than performances, so maybe using functions should be encouraged. I mean, in your case I'd probably use them unless there is a problem
What to do if you don't want to use a function? Well, there are other techniques:
- Mark the function as inline; this is a hint for the compiler not to create a function but to replicate this every time. This is only a hint, so the compiler may ignore this
- Instead of a function write a macro. This will be substituted every time, but the code will be maintainable. As a drawback, it is much harder to debug with the usual methods.
Just a remark: usually smart compilers can guess what is the best option (inline or function) on their own also for non-inline functions. So you can also trust the compiler in 90% of the cases
-
1You haven't mentioned optimization: if you use a function only once the compiler will most likely just place the code inline, thus avoiding the overhead of a function. You can also force a function to be inline, so you have the convenience of no duplicate code coupled with the efficience of inline code.Majenko– Majenko2017年11月27日 15:18:24 +00:00Commented Nov 27, 2017 at 15:18
-
The optimization is in the last remark; I could have highlighted it more. Moreover how can you force the compiler to inline? I thought that the "inline" keyword was just a hint; is there another keyword to force the inlining?frarugi87– frarugi872017年11月27日 21:29:31 +00:00Commented Nov 27, 2017 at 21:29
-
1
__attribute__((always_inline))
.Majenko– Majenko2017年11月27日 22:05:57 +00:00Commented Nov 27, 2017 at 22:05
The reason I would tend towards the second method more is there is less opportunity for bugs in the second version.
If storage size is a major concern and you know that repeating the code requires less storage, then I would #define it as a macro and get the best of both worlds.
You could improve the code though. At the moment you are passing copies of the variable into functions, passing const references might use less room, void checkBack(const TS_Point& p){
-
using
void checkBack(const TS_Point& p)
indeed reduced the size by 80 Bytes. Thank you for that!Lehue– Lehue2017年11月27日 14:42:15 +00:00Commented Nov 27, 2017 at 14:42 -
What seems strange though, is that
const type& variable
only reduces size with theTS_Point
variables, not withint
,uint16_t
or other normal types, where it increases size. I know this is not the question, but do you know the reason for that?Lehue– Lehue2017年11月27日 14:54:31 +00:00Commented Nov 27, 2017 at 14:54
Explore related questions
See similar questions with these tags.