7

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 Nov 27 '17 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 code – frarugi87 Nov 27 '17 at 14:44
  • 2
    Also (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 Nov 27 '17 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 Nov 27 '17 at 14:48
5

It.... depends

A call to function involves a few things

  1. Save the context
  2. Move the parameter(s) to the appropriate registers
  3. Enter the function
  4. Execute
  5. Eventually save the return value to a register
  6. Restore the context
  7. 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

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

  • 1
    You 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 Nov 27 '17 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 Nov 27 '17 at 21:29
  • 1
    __attribute__((always_inline)). – Majenko Nov 27 '17 at 22:05
2

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 Nov 27 '17 at 14:42
  • What seems strange though, is that const type& variable only reduces size with the TS_Point variables, not with int, 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 Nov 27 '17 at 14:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.